SwiftUI中的弹窗

冰岩作坊 June 1, 2024

系统弹窗

在SwiftUI中,iOS官方贴心地为我们实现了多种弹窗形式,包括Alert、confirmationDialog,即系统弹窗。

Alert

Alert是一个简单的弹窗,用于向用户显示一条消息和一个或多个按钮,以便用户可以选择相应的操作。正如它的名字一样,Alert通常用于显示紧急或重要的消息。我们可以通过 .alert() 来创建Alert。举个例子:

1
struct ContentViewView         .alert(isPresented: $showAlert)     }}

Alert当点击按钮时,更改控制变量showAlert,弹出Alert。在警告框弹出的情况下,只能点击确认/取消按钮来退出当前视图。

Alert 的title、message和 dismissButton的样式(如颜色、字体)是由系统控制的,不可以直接通过修改Text视图的属性来改变。这是为了确保 Alert 与系统外观保持一致,例如light mode和dark mode的区别。

当有多个Alert时,可以用enum枚举显示不同的Alert:

1
struct ContentViewView     }     var body: some View             Button("显示第二个Alert")         }        // 不同的alertType对应不同的Alert        .alert(item: $alertType)         }    }}

confirmationDialog

confirmationDialog 是一个更为灵活的弹窗,它在用户执行某个操作时,用多个按钮提供不同的选择。在iPhone中会从屏幕底部滑出。

1
struct ContentViewView         .confirmationDialog(""isPresented: $showActionSheet, titleVisibility: .hidden)             Button("删除"role: .destructive) {}            Button("取消"role: .cancel) {}        }    }}

confirmationDialog### 自定义弹窗

在许多场景中,只有这样的系统弹窗实在是有点让人难以接受。所以一般会使用自定义的弹窗。

Overlay

Overlay 是一个视图修饰符,它可以用来在现有视图上层添加一个新的视图层。其大致结构如下:

1
struct ContentViewView         .overlay(            // 判断是否显示弹窗            showingPopup ? popupOverlayView : nil        )    }    // 弹窗的视图    var popupOverlayViewsome View          // 为了模拟弹窗,给弹窗外的背景增加一个遮罩         .background(             Color.black.opacity(0.5)                 .edgesIgnoringSafeArea(.all)                 .onTapGesture                  }         )     }}

这时可以发现,Overlay和ZStack的意义几乎一样,都是在“垂直屏幕方向”增加视图,类似的也有相应的实现:

1
struct ContentViewView             // 要显示弹窗            if showingPopup                 // 第三层,弹窗内容,额外设置一个视图                PopupView(showingPopup: $showingPopup)                    .frame(width: 300, height: 200)                    .background(Color.white)                    .cornerRadius(10)                    .position(x: UIScreen.main.bounds.width / 2, y: UIScreen.main.bounds.height / 2)            }        }        .animation(.easeInOut, value: showingPopup)    }}struct PopupViewView         .onTapGesture         }    }}

sheet

sheet 是一个用来展示一个新视图的修饰符,这个新视图会覆盖在当前视图上。在视觉上,有“旧页面沉底,新页面弹出”的效果。因此sheet的页面是介于弹窗和单独页面之间的状态,与原页面有很强的逻辑关联。其适用情景也需要满足这一要求:

1
struct ContentViewView         .sheet(isPresented: $showingSheet)     }}struct sheetViewView         // .presentationDetents([.fraction(0.3)])    }}

其中presentationDetents是一个很炫酷的功能,它可以控制sheet的展示范围。.fraction(0.3)表示只会弹出到屏幕的30%,如果多加几个数字,就会变成分段推出的效果。

上面的showingSheet是基于布尔值的控制,也可以用标识符控制,使用示例如下:

1
enum SheetTypeIdentifiable }struct ContentViewView             Button("Show Second Sheet")         }        .sheet(item: $activeSheet)         }    }}

总结

实际开发中,弹窗使用之广泛使得开发者常常会把弹窗封装起来,作为一个通用的组件,以方便反复使用。总而言之,弹窗是一个贴合app使用逻辑并广泛运用的场景,合理的弹窗设计和实现有重要的意义和价值。