Как поместить форму в модальный интерфейс SwiftUI?
2 ответа
Решение
Два подхода
Вот два примера способов создания пользовательского модального окна.
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")
}
}
}
}
}
Возможно, второй подход даже лучше. С этим у меня тоже получилась вроде как работает анимация.
import SwiftUI
struct ContentView: View {
@State var flag = false
var body: some View {
ZStack {
VStack {
Text("Title").font(.largeTitle)
Toggle(isOn: $flag) {
Text("Show Moda' on")
}.padding(100)
Spacer()
}.disabled(flag)
if flag {
Color.gray.opacity(0.4).edgesIgnoringSafeArea(.all)
VStack {
Text("label")
Button(action: {
self.flag.toggle()
}) {
Text("Close")
}
}
.frame(width: 300, height: 200, alignment: .center)
.background(Color.primary.colorInvert()).cornerRadius(50)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}