Два подхода
Вот два примера способов создать пользовательский модал.
1. С .overlay()
import SwiftUI
struct ContentView: View { // your main view
@State var showModal: Bool = false
var body: some View {
NavigationView {
Button(action: {
self.showModal.toggle()
}) {
HStack {
Image(systemName: "plus.circle.fill")
.imageScale(.large)
Text("Show Modal")
}
}
.navigationBarTitle("Welcome")
}
.navigationViewStyle(StackNavigationViewStyle())
.overlay(ModalView(showModal: $showModal))
}
}
struct ModalView: View { // draws a semi-transparent rectangle that contains the modal
@Binding var showModal: Bool
var body: some View {
Group {
if showModal {
Rectangle()
.foregroundColor(Color.black.opacity(0.5))
.edgesIgnoringSafeArea(.all)
.overlay(
GeometryReader { geometry in
RoundedRectangle(cornerRadius: 16)
.foregroundColor(.white)
.frame(width: min(geometry.size.width - 100, 300), height: min(geometry.size.height - 100, 200))
.overlay(ModalContentView(showModal: self.$showModal))
}
)
}
}
}
}
struct ModalContentView: View { // the real modal content
@Binding var showModal: Bool
var body: some View {
VStack {
Text("Modal Content")
Button(action: {
self.showModal.toggle()
}) {
HStack {
Image(systemName: "xmark.circle.fill")
.imageScale(.large)
Text("Close Modal")
}
}
}
}
}
2. С ZStack
struct ContentView: View {
@State var showModal: Bool = false
var body: some View {
NavigationView {
ZStack {
Button(action: {
withAnimation {
self.showModal.toggle()
}
}) {
HStack {
Image(systemName: "plus.circle.fill")
.imageScale(.large)
Text("Show Modal")
}
}
if showModal {
Rectangle() // the semi-transparent overlay
.foregroundColor(Color.black.opacity(0.5))
.edgesIgnoringSafeArea(.all)
GeometryReader { geometry in // the modal container
RoundedRectangle(cornerRadius: 16)
.foregroundColor(.white)
.frame(width: min(geometry.size.width - 100, 300), height: min(geometry.size.height - 100, 200))
.overlay(ModalContentView(showModal: self.$showModal))
}
.transition(.move(edge: .bottom))
}
}
.navigationBarTitle("Welcome")
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
struct ModalContentView: View {
@Binding var showModal: Bool
var body: some View {
VStack {
Text("Modal Content")
Button(action: {
withAnimation {
self.showModal.toggle()
}
}) {
HStack {
Image(systemName: "xmark.circle.fill")
.imageScale(.large)
Text("Close Modal")
}
}
}
}
}
Может быть, этот второй подход еще лучше. С этим я также получил анимацию своего рода работы.