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

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

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


样式预览

image.png

弹窗视图

我们来分析下“新建发布”弹窗的内容,它包括一个提示的下拉条,一排横向布局的发布功能按钮,一个关闭弹窗的按钮。

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

// 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视图中组合样式视图内容,示例:

交互动画

弹出关闭

完成了弹窗视图后,我们回到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变量关闭弹窗。

项目预览

完成全部后,我们整体预览下效果。

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

快来动手试试吧。

 



相关文章
|
7月前
|
小程序 IDE 搜索推荐
【社区每周】小程序新增自定义tabBar功能;支持指定默认启动首页(2022年6月第三期)
【社区每周】小程序新增自定义tabBar功能;支持指定默认启动首页(2022年6月第三期)
72 0
|
4月前
|
图形学
小功能⭐️Unity判断是否单击到了UI
小功能⭐️Unity判断是否单击到了UI
|
7月前
|
Shell 开发工具 git
聊天功能演示系统发布后出现有些页面滚动与鼠标点击问题解决
聊天功能演示系统发布后出现有些页面滚动与鼠标点击问题解决
45 0
|
7月前
|
小程序 开发者
【功能上新】小程序自定义组件observers正式发布!
【功能上新】小程序自定义组件observers正式发布!
113 0
|
存储
发布&选择发布,使用SwiftUI搭建一个新建发布弹窗(上)
发布&选择发布,使用SwiftUI搭建一个新建发布弹窗(上)
110 0
WebStorm2023新版设置多个窗口,支持同时显示多个项目工程
WebStorm2023新版设置多个窗口,支持同时显示多个项目工程
181 0
|
移动开发 weex
Weex如何实现对话框 #45
Weex如何实现对话框 #45
109 0
|
前端开发
前端工作总结299-uni-发布详情页样式修改
前端工作总结299-uni-发布详情页样式修改
125 0
前端工作总结299-uni-发布详情页样式修改
|
IDE Shell 开发工具
【实测】django项目右上角没有自动出现启动按钮怎么办?
【实测】django项目右上角没有自动出现启动按钮怎么办?
【实测】django项目右上角没有自动出现启动按钮怎么办?
|
存储 安全 容器
SwiftUI极简教程37:构建一个AppStore应用市场推荐页面(下)
承接上一章的内容,我们继续完成构建一个AppStore应用市场推荐页面。 本章我们完成最难的部分,即摘要视图和完整视图的页面状态切换。
296 0
SwiftUI极简教程37:构建一个AppStore应用市场推荐页面(下)