携手创作,共同生长!这是我参与「日新方案 8 月更文应战」的第24天,点击检查活动详情。

接受上一章节的内容,在上一章节中,咱们完结了“新建发布”的入口背景蒙层的搭建,那么本章来进入要点,咱们来完结弹窗的交互。

款式预览

发布&选择发布,使用SwiftUI搭建一个新建发布弹窗(下)

弹窗视图

咱们来剖析下“新建发布”弹窗的内容,它包含一个提示的下拉条,一排横向布局的发布功用按钮,一个封闭弹窗的按钮。

咱们构建一个新的视图,示例:

// MARK: 底部弹窗
struct SlideOutMenu: View {
@Binding var showMaskView: Bool
 var body: some View {
   VStack {
   Spacer()
    //构建弹窗视图元素
  } 
 }
}

上述代码中,咱们创立了一个新视图SlideOutMenu。以及还运用@Binding声明晰一个变量,便利咱们在ContentView视图中做双向绑定。由于弹窗在底部,咱们运用VStack纵向布局,然后运用Spacer将弹窗撑开到底部。

完结后,咱们来完结弹窗的款式部分。

下拉条

咱们一块一块内容完结它,首先是下拉条,示例:

// 下拉条
func pullDownBtnView() -> some View {
Rectangle()
.foregroundColor(Color(.systemGray4))
.cornerRadius(30)
.frame(width: 50, height: 5)
}

上述代码中,咱们构建了一个Rectangle矩形,并赋予了颜色systemGray4灰色和圆角,尺寸咱们运用规则的长宽。

发布功用按钮

发布功用按钮部分,由于具有相同的款式,咱们能够运用结构体的办法构建根底款式,再在视图中调用,也能够运用创立视图的办法构建根底款式再调用。两种办法都能够运用,示例:

// 操作功用
func operateBtnView(image: String, text: String) -> some View {
Button(action: {
self.showMaskView = false
}) {
VStack(spacing: 15) {
Image(systemName: image)
.font(.system(size: 30))
.foregroundColor(.black)
.frame(width: 80, height: 80)
.background(Color(.systemGray6))
.cornerRadius(8)
Text(text)
.font(.system(size: 17))
.foregroundColor(.black)
}
}
}

上述代码中,咱们构建了一个结构视图operateBtnView,传入两个String类型的变量imagetext,别离代表操作按钮中的图标图片和操作按钮名称。

当咱们点击按钮的时分,切换showMaskView状况封闭蒙层。

封闭按钮

封闭按钮款式也比较简单,咱们依旧独自构建款式部分,示例:

// 封闭按钮
func colseBtnView() -> some View {
Button(action: {
self.showMaskView = false
}) {
Image(systemName: "xmark")
.font(.system(size: 24))
.foregroundColor(.gray)
.padding(.bottom, 20)
}
}

上述代码中,咱们独自构建按款式视图colseBtnView。当咱们点击封闭按钮的时分,也调用切换showMaskView状况封闭蒙层。

款式组合

完结上述3个视图后,咱们在SlideOutMenu视图中组合款式视图内容,示例:

// MARK: 底部弹窗
struct SlideOutMenu: View {
@Binding var showMaskView: Bool
var body: some View {
VStack {
Spacer()
   //构建弹窗视图元素
     VStack {
// 下拉条
pullDownBtnView()
Spacer()
// 操作按钮
HStack(spacing: 20) {
operateBtnView(image: "magazine.fill", text: "写文章")
operateBtnView(image: "doc.plaintext.fill", text: "发沸点")
operateBtnView(image: "book.fill", text: "提问题")
operateBtnView(image: "paperplane.fill", text: "传资源")
}
Spacer()
// 封闭按钮
colseBtnView()
}
.padding()
.frame(maxWidth: .infinity, maxHeight: 320)
.background(Color.white)
.cornerRadius(10, antialiased: true)
}.edgesIgnoringSafeArea(.bottom)
}
}

发布&选择发布,使用SwiftUI搭建一个新建发布弹窗(下)

交互动画

弹出封闭

完结了弹窗视图后,咱们回到ContentView视图中,将弹窗视图附上,示例:

var body: some View {
ZStack {
VStack {
topBarMenu()
Spacer()
}
if showMaskView {
MaskView(showMaskView: $showMaskView)
   SlideOutMenu(showMaskView: $showMaskView)
.transition(.move(edge: .bottom))
.animation(.interpolatingSpring(stiffness: 200.0, damping: 25.0, initialVelocity: 10.0))
}
}
}

上述代码中,咱们依据showMaskView变量状况决定是否展现背景蒙层视图和弹窗视图,然后在展现SlideOutMenu新建发布弹窗时,运用transition过渡和animation动画加了一个从下向上展现的过渡动画。

向下拖动封闭

新建发布弹窗除了惯例的点击封闭按钮封闭弹窗外,点击弹窗向下拖动时封闭弹窗,要实现这个功用,咱们回到SlideOutMenu弹窗视图中,首要声明2个变量,示例:

@State private var offsetY = CGSize.zero
@State var isAllowToDrag: Bool = false

上述代码中,offsetY变量存储拖动时弹窗Y轴的方位,用来判别用户在向上拖动还是向下拖动,也为了确认向下拖动Y轴到某一方位的,触发封闭弹窗交互。

变量isAllowToDrag是接受offsetY变量,当咱们判别向上拖动时,禁用弹窗拖动,防止弹窗向上拖动,确保只能向下拖动。

然后在SlideOutMenu主要内容中运用拖动修饰符,示例:

// MARK: 底部弹窗
struct SlideOutMenu: View {
@Binding var showMaskView: Bool
var body: some View {
VStack {
   //躲藏了弹窗视图代码
}
.padding()
.frame(maxWidth: .infinity, maxHeight: 320)
.background(Color.white)
.cornerRadius(10, antialiased: true)
   .offset(y: isAllowToDrag ? offsetY.height : 0)
   .gesture(
DragGesture()
.onChanged { gesture in
// 假如向下拖动
if gesture.translation.height > 0 {
self.isAllowToDrag = true
self.offsetY = gesture.translation
}
}
.onEnded { _ in
// 假如拖动方位大于100
if (self.offsetY.height) > 100 {
self.showMaskView = false
} else {
self.offsetY = .zero
}
}
)
}.edgesIgnoringSafeArea(.bottom)
}
}

上述代码中,咱们给弹窗内容加了offset偏移量修饰符,拖动时,假如isAllowToDrag答应拖动,则拖动方位为offsetY.height偏移的Y轴方位,否则便是0。

然后运用gesture手势修饰符,运用DragGesture拖着手势,当onChanged拖动改动时,先判别是不是向下拖动,假如是则启用isAllowToDrag变量,然后拖动后让视图回到本来的方位。

当弹窗视图onEnded拖动结束时,判别拖动的Y轴的方位offsetY.height是不是大于100,也便是弹窗宽度的大约1/3的方位,假如时则修改showMaskView变量封闭弹窗。

项目预览

完结全部后,咱们全体预览下作用。

发布&选择发布,使用SwiftUI搭建一个新建发布弹窗(下)

恭喜你,完结了本章的全部内容!

快来着手试试吧。

假如本专栏对你有帮助,不妨点赞、谈论、关注~