iOS开发 SwitftUI 13:提示、弹窗、上下文菜单

移动端没有桌面的窗口机制,各种弹窗都是系统功能。

目录

[.sheet 弹窗](#.sheet 弹窗)

[.fullScreenCover 全屏弹窗](#.fullScreenCover 全屏弹窗)

[.actionSheet 选项弹窗](#.actionSheet 选项弹窗)

[.alert 告警](#.alert 告警)

[.contextMenu 上下文菜单](#.contextMenu 上下文菜单)

汇总代码


.sheet 弹窗

sheet是一种弹窗机制,目前的默认实现是从屏幕下端升起,覆盖屏幕的绝大部分。

sheet属于整个屏幕,虽然把.sheet代码放在最外层符合逻辑,但实际上放在哪一层都没有关系,效果都是一样的。

基本的sheet用法:

Swift 复制代码
    @State var b = false
    @State var str = "info"

    var body: some View {
        Form {
            Button {b = true}label: {
                Text("打开sheet")
            }

            Text(str)
        }
        .sheet(isPresented: $b) {
            Text("关闭")
                .onTapGesture {
                    str = str + "+1"
                    b = false
                }
        }
    }

sheet需要一个变量来指示是否显示,需要关闭的时候设置变量为false即可。很明显,sheet是当前页面的一部分,只是根据指示显示出来。

初始:

点一下"打开sheet":

sheet打开,占据屏幕绝大部分。再点一下"关闭":

"info"变成了"info+1",符合预期。

由于界面和数据完全通过绑定变量交互,不用太关心sheet对象再次打开时是重新创建还是显示原来的对象,不像桌面程序,要考虑对象的创建和显示/隐藏。

.fullScreenCover 全屏弹窗

只需要简单地把.sheet替换成.FullScreenCover即可,效果:

除了全屏化没别的区别。

.actionSheet 选项弹窗

注意,已经被标记为过时,推荐用confirmationDialog代替。

ActionSheet提供类似菜单的操作,显示方式和前面的两种一样,用一个变量来表示是否显示,选项弹窗的关键代码如下:

Swift 复制代码
        .actionSheet(isPresented: $b) {
            return ActionSheet(
                title: Text("操作"),
                message: Text("随便选一个"),
                buttons: [
                    .cancel(
                        Text("取消"),
                        action: { str = str + "+cancel" }),
                    .destructive(
                        Text("危险 动作1"),
                        action: { str = str + "+destructive" }
                    ),
                    .default(
                        Text("默认 动作2"),
                        action: { str = str + "+default" }
                    ),
                ]
            )
        }

效果:

上面的代码在处理动作的时候并没有重置绑定变量b,设置的取消按钮也没有显示,但其实只需要点击弹窗以外的区域弹窗就会关闭,而且,任何一个动作结束都会自动重置绑定变量。

点击空白处取消:

再弹出来一次,点击一个选项:

动作都是正确执行的。

我们创建按钮的时候用了.destructive和.default,这两个是按钮的"角色",前一个表示是破坏性的,所以系统自动使用红色显示,后一个是默认,系统使用黑色显示。

.alert 告警

写法跟actionSheet差不多:

Swift 复制代码
        .alert(isPresented: $bAlert) {
            return Alert(title: Text("告警")
                         ,message: Text("确定吗?")
                         ,primaryButton: .destructive(Text("确认")){str = str + "+ok"}
                         ,secondaryButton: .default(Text("取消")){str = str + "+canecl"}
                         )
        }

效果:

说实话这东西真没有太多自定义的必要,但是从交互设计角度来说,文字应该居中显示。

.contextMenu 上下文菜单

上下文菜单需要通过长按呼出。跟前面的几个不同,不需要变量来指示是否显示,而且显示位置和修饰的对象有关。

下面的代码分别给整体和一个单独的Text设置了上下文菜单:

Swift 复制代码
    var body: some View {
        Form {
            //。。。。。。

            Text(str)
                .contextMenu {
                    Button("上下文菜单3") {
                        str = str + "+contextMenu3"
                    }
                    Button("上下文菜单4") {
                        str = str + "+contextMenu4"
                    }
                }
        }
        //。。。。。。
        .contextMenu {
            Button("上下文菜单1") {
                str = str + "+contextMenu1"
            }
            Button("上下文菜单2") {
                str = str + "+contextMenu2"
            }
        }
    }

长按Text的效果:

长按其余部分的效果:

汇总代码

本文的完整代码:

Swift 复制代码
import SwiftUI

struct SwiftUIViewPopup: View {
    @State var bSheet = false
    @State var bFullScreenCover = false
    @State var bActionSheet = false
    @State var bAlert = false
    @State var str = "info"

    var body: some View {
        Form {
            Button {
                bSheet = true
            } label: {
                Text("打开sheet")
            }
            Button {
                bFullScreenCover = true
            } label: {
                Text("打开FullScreenCover")
            }
            Button {
                bActionSheet = true
            } label: {
                Text("打开ActionSheet")
            }
            Button {
                bAlert = true
            } label: {
                Text("打开Alert")
            }

            Text(str)
                .contextMenu {
                    Button("上下文菜单3") {
                        str = str + "+contextMenu3"
                    }
                    Button("上下文菜单4") {
                        str = str + "+contextMenu4"
                    }
                }
        }
        .sheet(isPresented: $bSheet) {
            Text("关闭")
                .onTapGesture {
                    str = str + "+1"
                    bSheet = false
                }
        }
        .fullScreenCover(isPresented: $bFullScreenCover) {
            Text("关闭")
                .onTapGesture {
                    str = str + "+a"
                    bFullScreenCover = false
                }
        }
        .actionSheet(isPresented: $bActionSheet) {
            return ActionSheet(
                title: Text("操作"),
                message: Text("随便选一个"),
                buttons: [
                    .cancel(
                        Text("取消"),
                        action: { str = str + "+cancel" }
                    ),
                    .destructive(
                        Text("危险 动作1"),
                        action: { str = str + "+destructive" }
                    ),
                    .default(
                        Text("默认 动作2"),
                        action: { str = str + "+default" }
                    ),
                ]
            )
        }
        .alert(isPresented: $bAlert) {
            return Alert(
                title: Text("告警"),
                message: Text("确定吗?"),
                primaryButton: .destructive(Text("确认")) { str = str + "+ok" },
                secondaryButton: .default(Text("取消")) { str = str + "+canecl" }
            )
        }
        .contextMenu {
            Button("上下文菜单1") {
                str = str + "+contextMenu1"
            }
            Button("上下文菜单2") {
                str = str + "+contextMenu2"
            }
        }
    }
}

#Preview {
    SwiftUIViewPopup()
}
相关推荐
HouWan3 小时前
SwiftUI 小技巧:如何读取 SwiftUI Font 的详细信息
ios·swiftui·apple
李游Leo4 小时前
HarmonyOS 7 实战开发 05:把页面做到可上线状态
ios·harmonyos
终端安全笔记9 小时前
描述文件、企业证书、MDM 不是三个名字,是三层
android·ios·智能手机
传奇开心果编程9 小时前
【SwiftUI入门练中学】第1课 从零开始
学习·ui·ios·swiftui·swift
丿Wayne15 小时前
iOS Token 刷新实战(Actor 避免并发重复刷新)
ios·swift·token·actor·swift并发
终端安全笔记1 天前
iOS 27 给了租赁一个新工具,但它只认受监督的设备
android·网络·安全·ios
大熊猫侯佩1 天前
独立 App 首发完成 iPhone Duo 展开态适配
ios·swiftui·swift
光影少年2 天前
setImmediate 和 setTimeout(0) 的区别
android·前端·react.js·ios·前端框架
2501_916008892 天前
SSE 和 gRPC 流式接口如何抓包,调试 SSE 与 gRPC 流式接口
网络协议·计算机网络·网络安全·ios·adb·https·udp