[SwiftUI]系统弹窗和自定义弹窗

一、系统弹窗

在 SwiftUI 中,.alert 是一个修饰符,用于在某些条件下显示一个警告对话框。Alert 可以配置标题、消息和一系列的按钮。每个按钮可以是默认样式、取消样式,或者是破坏性的样式,它们分别对应不同的用户操作。

1.Alert

基本用法

只显示一个按钮,通常用于确认消息。

struct ContentView: View {@State private var showAlert = falsevar body: some View {Button("Show Basic Alert") {showAlert = true}.alert(isPresented: $showAlert) {Alert(title: Text("Basic Alert"),message: Text("This is a basic alert with a single button."),dismissButton: .default(Text("OK")))}}
}

示意图:

注意:

Alert 的 titlemessage 和 dismissButton 的样式(如颜色、字体)是由系统控制的,不可以直接通过修改 Text 视图的属性来改变。这是为了确保 Alert 对话框保持一致的系统外观和行为,也为了确保它符合当前的操作系统主题,无论是暗模式还是亮模式。

因此,即使你尝试在 Text 视图中使用 .foregroundColor 或 .font 等修饰符,这些样式也不会应用到 Alert 中的 Text 上。

如果你需要定制的弹窗样式,需要创建一个自定义的弹窗视图,并使用 .sheet 或者其他视图容器来显示它。这样就可以完全控制弹窗视图的外观和布局,见下面自定义弹窗部分。

多个按钮

展示多个按钮,包括取消按钮和其他操作。

struct ContentView: View {@State private var showAlert = falsevar body: some View {Button("Show Alert with Multiple Buttons") {showAlert = true}.alert(isPresented: $showAlert) {Alert(title: Text("Multiple Buttons"),message: Text("This alert has multiple buttons."),primaryButton: .destructive(Text("Delete")) {// Handle delete action},secondaryButton: .cancel())}}
}

示意图:

.alert(isPresented: $showAlert) {Alert(title: Text("Multiple Buttons"),message: Text("This alert has multiple buttons."),primaryButton: .cancel(Text("NO")) {},secondaryButton: .default(Text("Logout")) {})
}

示意图:

注意:

Alert中最多只能添加两个按钮,被.cancel修饰的按钮一定会加粗并展示在左边,

.cancel最多只能修饰一个按钮,同时修饰两个按钮时会报错
"UIAlertController can only have one action with a style of UIAlertActionStyleCancel"

使用枚举来显示不同的Alerts

使用 Identifiable 协议来区分不同的警告类型,根据不同的情况显示不同的警告。

struct ContentView: View {@State private var alertType: AlertType? = nilenum AlertType: Identifiable {case first, secondvar id: Int {hashValue}}var body: some View {VStack {Button("Show First Alert") {alertType = .first}Button("Show Second Alert") {alertType = .second}}.alert(item: $alertType) { type -> Alert inswitch type {case .first:return Alert(title: Text("First Alert"),message: Text("This is the first alert."),dismissButton: .default(Text("OK")))case .second:return Alert(title: Text("Second Alert"),message: Text("This is the second alert."),primaryButton: .default(Text("NO")) {},secondaryButton: .default(Text("YES")) {})}}}
}

这种方式也比较常用,比如同一个页面有多个弹窗时,总不至于傻兮兮去定义多个@State吧。

2.ActionSheet

ActionSheet 是一种展示给用户一组操作或选择列表的方式。它与 Alert 类似,但通常用于提供两个或更多选项。ActionSheet 在 iPad 上以弹出的形式呈现,在 iPhone 上则从屏幕底部滑出。

import SwiftUIstruct ContentView: View {@State private var showActionSheet = falsevar body: some View {Button("Show Action Sheet") {showActionSheet = true}.actionSheet(isPresented: $showActionSheet) {ActionSheet(title: Text("What do you want to do?"),message: Text("There's only one option..."),buttons: [.default(Text("Option 1")) {// Handle Option 1 action},.destructive(Text("Delete")) {},.cancel()])}}
}

示意图:

注意:

与Alert一样,被.cancel修饰的按钮会被加粗并固定在底部,且最多只能有一个按钮被.cancel修饰。

二、自定义弹窗

1.使用 Overlay 创建自定义弹窗

Overlay 是一个视图修饰符,它可以用来在现有视图上层添加一个新的视图层。

import SwiftUIstruct ContentView: View {// 弹窗的显示状态@State private var showingPopup = falsevar body: some View {VStack {// 主视图内容Button("Show Popup") {withAnimation {showingPopup.toggle()}}.frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.white)}// 在这里使用 .overlay 添加弹窗.overlay(// 判断是否显示弹窗showingPopup ? popupOverlayView : nil)}// 弹窗的视图var popupOverlayView: some View {VStack {Spacer()// 弹窗内容VStack {Text("Basic Alert").font(.headline).padding()Text("This is a basic alert with a single button.").multilineTextAlignment(.center).padding(.horizontal, 10)Button("Dismiss") {withAnimation {showingPopup = false}}.padding()}.frame(maxWidth: .infinity, minHeight: 200).background(Color.white).cornerRadius(12).shadow(radius: 8).padding(.horizontal, 30)Spacer()}.background(// 背景遮罩Color.black.opacity(0.5).edgesIgnoringSafeArea(.all).onTapGesture {withAnimation {showingPopup = false}})}
}

示意图:

2.使用 ZStack 创建自定义弹窗

ZStack 是一个用来叠加视图的容器,它可以让你在同一个屏幕坐标空间中放置多个视图。当你使用 ZStack 创建弹窗时,你通常会在同一视图层次中添加弹窗视图和背景遮罩。这种方式直观且容易理解,尤其是当你的弹窗视图需要位于内容的正中央时。

基础用法

import SwiftUIstruct ContentView: View {@State private var showingPopup = falsevar body: some View {ZStack {// 主视图内容Button("Show Popup") {showingPopup.toggle()}if showingPopup {// 弹窗背景Color.black.opacity(0.4).edgesIgnoringSafeArea(.all).onTapGesture {showingPopup = false}// 弹窗内容CustomPopupView(showingPopup: $showingPopup).frame(width: 300, height: 200).background(Color.white).cornerRadius(10).shadow(radius: 10).position(x: UIScreen.main.bounds.width / 2, y: UIScreen.main.bounds.height / 2).transition(.scale)}}.animation(.easeInOut, value: showingPopup)}
}struct CustomPopupView: View {@Binding var showingPopup: Boolvar body: some View {VStack {Text("Basic Alert").font(.headline).padding()Text("This is a basic alert with a single button.").frame(alignment: .center).multilineTextAlignment(.center).font(.body).padding()Spacer()Button("Dismiss") {// 传递动作以关闭弹窗showingPopup = false// 可能需要使用一个绑定变量或闭包}.padding(.bottom)}.frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.white).cornerRadius(20).shadow(radius: 20)}
}

示意图:

 

封装后使用

import SwiftUIstruct ContentView: View {@State private var showAlertType: CustomAlertType? = nilvar body: some View {VStack {Button("Show Alert") {showAlertType = .Alert}}.customAlert($showAlertType, message: "toastText")}}
enum CustomAlertType: Int {case None = -1case Loading = 100case Toast = 101case Alert = 102
}extension View {/// 自定义弹窗func customAlert(_ alertType: Binding<CustomAlertType?>, message: String = "" , finish: ((String?) -> ())? = nil) -> some View {ZStack {selflet type = alertType.wrappedValueif type != nil && type != .None {if type == .Alert {Color.black.opacity(0.3).edgesIgnoringSafeArea(.all).onTapGesture {alertType.wrappedValue = .None}CustomPopupView(showAlertType: alertType, message: message, finish: finish).popupAnimation()} else if type == .Toast {}}}}}struct PopupAnimationModifier: ViewModifier {@State private var isVisible: Bool = falsefunc body(content: Content) -> some View {content.scaleEffect(isVisible ? 1 : 0.9).onAppear {withAnimation(.linear(duration: 0.15)) { // easeIn easeInOut easeOut linearisVisible = true}}}
}extension View {func popupAnimation() -> some View {self.modifier(PopupAnimationModifier())}}
import SwiftUIstruct CustomPopupView: View {@Binding var showAlertType: CustomAlertType?@State var message: Stringvar finish: ((String?) -> ())? = nilvar body: some View {VStack {Text("Alert").font(.headline).padding()Text(message).frame(alignment: .center).multilineTextAlignment(.center).font(.body).padding()Spacer()Button("OK") {showAlertType = nilfinish?(nil)}.padding(.bottom)}.frame(maxWidth: 300, maxHeight: 200).background(Color.white).cornerRadius(20).shadow(radius: 20)}
}

示意图:

3. 使用 sheet 创建半屏自定义弹窗

sheet 是一个用来展示一个新视图的修饰符,这个新视图会覆盖在当前视图上。通常 sheet 用于导航到另一个视图,比如详情页、编辑表单或者是分享菜单等。

sheet 修饰符可以通过多种方式使用,其中包括基于布尔值的呈现、使用可选的绑定对象来管理呈现以及使用标识符进行呈现。

.sheet(isPresented:)

基于布尔值的呈现

import SwiftUIstruct ContentView: View {@State private var showingSheet = falsevar body: some View {Button("Show Sheet") {showingSheet.toggle()}.sheet(isPresented: $showingSheet) {// Sheet 的内容SheetView()}}
}struct SheetView: View {var body: some View {Text("Here's the sheet!")}
}

.sheet(item:) 

使用可选的绑定对象
import SwiftUIstruct ContentView: View {@State private var selectedUser: User? = nilvar body: some View {Button("Show Sheet") {selectedUser = User(name: "John Doe") // 假设 User 是一个简单的数据模型}.sheet(item: $selectedUser) { user in// Sheet 的内容UserDetailsView(user: user)}}
}struct User: Identifiable {let id = UUID()let name: String
}struct UserDetailsView: View {var user: Uservar body: some View {Text("User Details for \(user.name)")}
}
使用标识符进行呈现
import SwiftUIstruct ContentView: View {@State private var activeSheet: SheetType? = nilvar body: some View {VStack {Button("Show First Sheet") {activeSheet = .first}Button("Show Second Sheet") {activeSheet = .second}}.sheet(item: $activeSheet) { item in// 根据不同的标识符显示不同的视图switch item {case .first:FirstSheetView()case .second:SecondSheetView()}}}
}enum SheetType: Identifiable {case first, secondvar id: Self { self }
}struct FirstSheetView: View {var body: some View {Text("This is the first sheet")}
}struct SecondSheetView: View {var body: some View {Text("This is the second sheet")}
}

示意图:

 

4.使用 fullScreenCover 创建全屏自定义弹窗

fullScreenCover 是一个视图修饰符,它用于展示一个全屏的覆盖视图。这个修饰符通常用于呈现一个全屏弹窗,比如登录页面、介绍页面或者任何需要从当前视图完全转移焦点的场景。

.fullScreenCover(isPresented:)

基于布尔值的呈现

import SwiftUIstruct ContentView: View {// 管理全屏弹窗的显示状态@State private var showingFullScreenPopup = falsevar body: some View {// 主视图的内容Button("Show Full Screen Popup") {// 显示全屏弹窗showingFullScreenPopup = true}// 使用 fullScreenCover 修饰符来显示全屏弹窗.fullScreenCover(isPresented: $showingFullScreenPopup) {// 传递 isPresented 绑定到弹窗视图,以便可以关闭弹窗FullScreenPopupView(isPresented: $showingFullScreenPopup)}}
}// 自定义全屏弹窗视图
struct FullScreenPopupView: View {// 绑定变量,用于控制弹窗的显示与隐藏@Binding var isPresented: Boolvar body: some View {ZStack {// 弹窗的背景Color.blue.edgesIgnoringSafeArea(.all)// 弹窗的内容VStack {Text("This is a full screen popup!").font(.largeTitle).foregroundColor(.white).padding()Button("Dismiss") {// 关闭弹窗isPresented = false}.font(.title).padding().background(Color.white).foregroundColor(.blue).cornerRadius(10)}}}
}

.fullScreenCover(item:)

import SwiftUIstruct ContentView: View {// 用于控制全屏弹窗的状态@State private var selectedFullScreenItem: FullScreenItem?var body: some View {VStack(spacing: 20) {// 触发全屏弹窗的按钮Button("Show FullScreen Cover") {selectedFullScreenItem = FullScreenItem(id: 2)}}// 全屏弹窗修饰符.fullScreenCover(item: $selectedFullScreenItem) { item inFullScreenCoverView(fullScreenItem: item)}}
}// 用于全屏弹窗的数据模型
struct FullScreenItem: Identifiable {let id: Int
}// 用于全屏弹窗的视图
struct FullScreenCoverView: View {var fullScreenItem: FullScreenItemvar body: some View {VStack {Text("FullScreen Cover View with item id: \(fullScreenItem.id)")Spacer()}.frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.blue)}
}

示意图:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/654191.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端qrcode生成二维码详解

文章目录 前言1、浏览器支持2、优点3、缺点4、相关方法5、安装及使用示例 前言 qrcode 是一个基于JavaScript的二维码生成库&#xff0c;主要是通过获取 DOM 的标签&#xff0c;再通过 HTML5 Canvas 绘制而成&#xff0c;不依赖任何库。 官方文档&#xff1a;https://www.npm…

Kafka-服务端-GroupCoordinator

在每一个Broker上都会实例化一个GroupCoordinator对象&#xff0c;Kafka按照Consumer Group的名称将其分配给对应的GroupCoordinator进行管理&#xff1b; 每个GroupCoordinator只负责管理Consumer Group的一个子集&#xff0c;而非集群中全部的Consumer Group。 请注意与Kaf…

Java项目:基于SSM框架实现的企业员工岗前培训管理系统(ssm+B/S架构+源码+数据库+毕业论文)

一、项目简介 本项目是一套ssm821基于ssm框架实现的企业员工岗前培训管理系统&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格…

NetExec:一款功能强大的自动化网络安全评估与漏洞测试工具

关于NetExec NetExec是一款功能强大的自动化网络安全评估与漏洞测试工具&#xff0c;该工具可以帮助广大研究人员以自动化的形式测试大型网络的安全&#xff0c;并通过利用网络服务漏洞来评估目标网络的安全态势。 支持的协议 1、SMB协议 2、LDAP协议 3、WinRM协议 4、MSSQL协…

go语言函数进阶

1.变量作用域 全局变量 全局变量是定义在函数外部的变量&#xff0c;它在程序整个运行周期内都有效。 在函数中可以访问到全局变量。 package mainimport "fmt"//定义全局变量num var num int64 10func testGlobalVar() {fmt.Printf("num%d\n", num) /…

vue-head 插件设置浏览器顶部 favicon 图标 - 动态管理 html 文档头部标签内容

目录 需求实现11. 安装插件2. 项目内 main.js 引入3. vue页面使用 实现2其他 需求 vue项目中浏览器页面顶部图标可配置 实现1 使用 vue-head 插件实现 vue-head 插件可实现 html 文档中 head 标签中的内容动态配置&#xff08;npm 官网 vue-head 插件&#xff09; 1. 安装插件 …

promethues基础概念

promethues是一个开源的系统监控以及报警系统&#xff0c;整个zabbix的功能&#xff0c;系统&#xff0c;网络&#xff0c;设备 promethues可以兼容网络和设置被&#xff0c;容器监控&#xff0c;告警系统&#xff0c;因为他和k8s是一个项目基金开发的产品&#xff0c;天生匹配…

代码随想录算法训练营第34天 | 1005.K次取反后最大化的数组和 134.加油站 135.分发糖果

K次取反后最大化的数组和 贪心局部最优&#xff1a;将绝对值大的负数变为正数&#xff0c;当前和变为最大&#xff1b;全局最优&#xff1a;整体获得最大和。 如果负数都变成正数之后&#xff0c;k > 0&#xff0c;仍然需要继续翻转&#xff0c;贪心局部最优&#xff1a;将最…

14.STM32F4 LCD屏幕概念及源码下载(LCD之一)

一、LCD液晶显示屏介绍 1、常见的显示设备 在目前市面上&#xff0c;常见的显示设备种类有&#xff1a;LED、显示数码管、点阵LED显示屏、LCD液晶显示屏&#xff0c;这几种设备的特点是&#xff1a; &#xff08;1&#xff09;LED LED灯是最简单的显示设备&#xff0c;它只有两…

天拓四方:物联网网关在机械制造企业的应用

随着物联网技术的不断发展&#xff0c;越来越多的机械制造企业开始探索如何利用物联网技术提升生产效率、降低运营成本。物联网网关作为物联网架构中的关键设备&#xff0c;能够实现设备间的数据交互与远程控制&#xff0c;为机械制造企业带来了巨大的商业价值。它能够实现设备…

漏洞原理XSS存贮型漏洞

漏洞原理XSS存贮型漏洞 XSS&#xff08;跨站脚本攻击&#xff09;是一种常见的Web安全漏洞&#xff0c;它允许攻击者将恶意代码注入到网页中&#xff0c;进而攻击用户的浏览器。存储型XSS漏洞是一种特定类型的XSS漏洞&#xff0c;它发生在Web应用程序中&#xff0c;其中用户输入…

小红叒战小紫

概率dp #include <iostream> #include <string> #include <stack> #include <vector> #include <queue> #include <deque> #include <set> #include <map> #include <unordered_map> #include <unordered_set> #…

在租户内启用SharePoint Embedded

要开启 SharePoint Embedded&#xff0c;你得是管理员&#xff0c;然后按照这些步骤操作&#xff1a; 登录到你的 SharePoint 管理中心。在左边的菜单里找到“设置”选项&#xff0c;点进去。 3. 在设置页面里找到“SharePoint Embedded 应用”。 4.如果这个功能还没开启&…

Android Settings 显示电池点亮百分比

如题&#xff0c;Android 原生 Settings 里有个 电池电量百分比 的选项&#xff0c;打开后电池电量百分比会显示在状态栏。 基于 Android 13 &#xff0c; 代码在 ./packages/apps/Settings/src/com/android/settings/display/BatteryPercentagePreferenceController.java &am…

【flutter项目类型】project type如何区分

通过项目中.metadata内容区分 如 # Used by Flutter tool to assess capabilities and perform upgrades etc. # # This file should be version controlled and should not be manually edited.version:revision: 85684f9300908116a78138ea4c6036c35c9a1236channel: stablep…

【大数据】Flink 架构(二):数据传输

《Flink 架构》系列&#xff08;已完结&#xff09;&#xff0c;共包含以下 6 篇文章&#xff1a; Flink 架构&#xff08;一&#xff09;&#xff1a;系统架构Flink 架构&#xff08;二&#xff09;&#xff1a;数据传输Flink 架构&#xff08;三&#xff09;&#xff1a;事件…

(Aliexpress)速卖通卖家通过自养号补单提高出单率

在跨境电商领域&#xff0c;有些卖家可能会遇到这样的问题&#xff1a;自己的速卖通店铺始终没有订单产生。那么&#xff0c;当速卖通店铺一直不出单时&#xff0c;我们应该如何进行补救呢&#xff1f;今天珑哥将围绕这个问题展开探讨&#xff0c;并分享一些提升速卖通店铺销量…

HCIP复习课(mpls实验)

1、IP配置&#xff1a; R1&#xff1a; R2&#xff1a; R3&#xff1a; R4&#xff1a; R5&#xff1a; R6&#xff1a; R7&#xff1a; R8&#xff1a; 2、rip&#xff0c;ospf配置&#xff1a; R2&#xff1a; R3&#xff1a; R4&#xff1a; R5&#xff1a; R6&#xff1a…

信创联盟--朗思科技加入证券基金行业信息技术应用创新联盟,共促金融信创发展

近期&#xff0c;证券基金行业信息技术应用创新联盟&#xff08;以下简称&#xff1a;信创联盟&#xff09;新一批成员单位名单公布&#xff0c;朗思科技LanSive凭借产品创新以及实践案例成功入选&#xff0c;正式成为信创联盟成员单位。 信创联盟由上交所联合行业券商倡议发起…

Threejs 展示——fbx 格式模型导入

文章目录 需求分析 需求 导入fbx 格式的模型数据 分析 需要准备 fbx 格式的数据&#xff0c;如下所示 <template><div id"three-canvas" /> </template> <script> // import { Color, MOUSE, PerspectiveCamera, Scene, WebGLRenderer } …