Custom Modal View
Custom Modal View 是一个轻量级的 SwiftUI 库,它可以让您展示完全可定制的模态对话框。
它的 API 构造与原生 .sheet(...)
视图修饰符类似,其使用方式很好地融入了现有的 SwiftUI 应用程序中。
安装
Swift Package Manager
只需将此仓库的 URL 添加到您的依赖项中。
https://github.com/jankaltoun/custom-modal-view
Cocoapods
如果您要通过 Cocoapods 使用此库,请将以下行添加到您的 Podfile 中。
pod 'CustomModalView'
平台支持
此库最适合在iOS和iPadOS上使用,但macOS也能正常工作。
代码也可以为tvOS和watchOS编译,但那里的UI范式有所不同,因此使用模态视图并不合适。
用法
请参阅示例项目了解iOS和macOS的示例。
创建模态视图
要创建模态视图,请在任何视图中使用 .modal(...)
视图修饰符。
您需要传递一个绑定到某个 Bool
或 Identifiable?
属性,以便模态知道何时显示和消失。其行为与 .sheet(...)
视图修饰符完全相同。
以下示例显示了绑定到 Bool
属性的初始化。
struct MainView: View {
@State var modalIsDisplayed = false
var body: some View {
Button(action: { self.modalIsDisplayed = true }) {
Text("Show modal")
}
.modal(isPresented: $modalIsDisplayed) {
Text("Hello world!")
.padding()
}
}
}
下一个示例显示了绑定到 Identifiable?
属性的初始化。
struct ContentView: View {
enum SomethingIdentifiable: Int, Identifiable {
case llama = 1
var id: Int {
rawValue
}
}
@State var somethingIdentifiable: SomethingIdentifiable? = nil
var body: some View {
Button(action: { self.somethingIdentifiable = .llama }) {
Text("Show modal")
}
.modal(item: $somethingIdentifiable) { item in
Text("Alpacas are the best!")
.padding()
}
}
}
关闭模态视图
默认情况下,点击模态视图后面的区域可以关闭它。此行为可以在(见模态视图样式部分)中修改。
如果您希望使用按钮关闭模态视图,可以使用 .modalPresentationMode
键来获取绑定到 ModalPresentationMode
的绑定并调用 dismiss()
。
您的视图应将该属性定义为 @Environment(\.modalPresentationMode) var modalPresentationMode: Binding<ModalPresentationMode>
。
示例如下。
import CustomModalView
struct ContentView: View {
@State var modalIsDisplayed = false
var body: some View {
Button(action: { self.modalIsDisplayed = true }) {
Text("Show modal")
}
.modal(isPresented: $modalIsDisplayed) {
DetailView()
}
}
}
struct DetailView: View {
@Environment(\.modalPresentationMode) var modalPresentationMode: Binding<ModalPresentationMode>
var body: some View {
VStack(spacing: 32) {
Text("I'm a modal")
Button(action: {
self.modalPresentationMode.wrappedValue.dismiss()
}) {
Text("Dismiss")
}
}
.padding()
}
}
另一种选择是仅将绑定传递给绑定模态视图的属性,并将它设置为 false
(或如果您的属性是 Identifiable?
,则为 nil
)。
这有点麻烦,但可以很容易地完成。
struct ContentView: View {
@State var modalIsDisplayed = false
var body: some View {
Button(action: { self.modalIsDisplayed = true }) {
Text("Show modal")
}
.modal(isPresented: $modalIsDisplayed) {
DetailView(isDisplayed: $modalIsDisplayed)
}
}
}
struct DetailView: View {
@Binding var isDisplayed: Bool
var body: some View {
VStack(spacing: 32) {
Text("I'm a modal.")
.fixedSize(horizontal: false, vertical: true)
Button(action: { self.isDisplayed = false }) {
Text("Dismiss")
}
}
.padding()
}
init(isDisplayed: Binding<Bool>) {
self._isDisplayed = isDisplayed
}
}
样式化模态视图
您可以随意设计自己的模态视图,并且有两个工具可供您使用:
- 样式化视图
- 样式化容器
视图样式化
视图样式化可以用来修改模态内容的显示效果。您可以使用所有 SwiftUI 工具来做到这一点。
例如,像以下示例中定义的模态。
struct ContentView: View {
@State var modalIsDisplayed = false
var body: some View {
Button(action: { self.modalIsDisplayed = true }) {
Text("Show modal")
}
.modal(isPresented: $modalIsDisplayed) {
Text("I'm a fancy Hello world!")
.frame(width: 200, height: 100, alignment: .topLeading)
.padding()
.background(Color.red)
.foregroundColor(.white)
}
}
}
将产生以下用户界面。
容器样式化
如果您需要调整角半径、模态背景或基本内容,则可以创建自己的模态样式。
定义自己的样式非常简单。首先创建一个遵循 ModalStyle
协议的 struct
,然后实现两个必需的函数。
使用这两个函数,您可以完全自定义背景和模态视图的外观,以及模态出现和消失时使用的动画。
struct DefaultModalStyle: ModalStyle {
let animation: Animation? = .easeInOut(duration: 0.5)
func makeBackground(configuration: ModalStyle.BackgroundConfiguration, isPresented: Binding<Bool>) -> some View {
configuration.background
.edgesIgnoringSafeArea(.all)
.foregroundColor(.black)
.opacity(0.3)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.zIndex(1000)
.onTapGesture {
isPresented.wrappedValue = false
}
}
func makeModal(configuration: ModalStyle.ModalContentConfiguration, isPresented: Binding<Bool>) -> some View {
configuration.content
.background(Color.white)
.clipShape(RoundedRectangle(cornerRadius: 16))
.zIndex(1001)
}
}
事实上,这正好是 DefaultModalStyle 实现的方式。
一种花哨的样式可能看起来像下面的例子。
import CustomModalView
struct FancyModalStyle: ModalStyle {
let animation: Animation? = .easeInOut(duration: 0.5)
func makeBackground(configuration: ModalStyle.BackgroundConfiguration, isPresented: Binding<Bool>) -> some View {
configuration.background
.edgesIgnoringSafeArea(.all)
.foregroundColor(.blue)
.opacity(0.3)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.zIndex(1000)
}
func makeModal(configuration: ModalStyle.ModalContentConfiguration, isPresented: Binding<Bool>) -> some View {
configuration.content
.background(Color.yellow)
.clipShape(RoundedRectangle(cornerRadius: 8))
.zIndex(1001)
}
}
struct ContentView: View {
@State var modalIsDisplayed = false
var body: some View {
Button(action: { self.modalIsDisplayed = true }) {
Text("Show modal")
}
.modal(isPresented: $modalIsDisplayed) {
Text("Hello world!")
.padding()
}
.modalStyle(FancyModalStyle())
}
}
该样式的结果如下截图所示。
作者
Jan Kaltoun, [email protected]
许可
请随意使用此代码。
如果您链接到此存储库或提及我是作者,我会很高兴!