如何在 SwiftUI 中模态地推动下一个屏幕充满
Posted
技术标签:
【中文标题】如何在 SwiftUI 中模态地推动下一个屏幕充满【英文标题】:How to Modally push next Screen to be full in SwiftUI 【发布时间】:2019-06-21 19:36:19 【问题描述】:我怎样才能推送下一个 SwiftUI 视图但在全屏上显示它而不像 Xcode 10 模态演示那样向下滑动功能。
我当前的实现,但它没有推到全屏(启用下拉和顶部的间隙):
btn
.presentation(
!showModal.value ?
nil :
Popover(content: destination, dismissHandler: onTrigger ?? )
)
【问题讨论】:
我认为这是一个缺失的功能,因为 SwiftUI (ios13) 仍处于测试阶段。 @UgoArangino 那么 Popover 是什么? ***.com/questions/58958858/… 【参考方案1】:我认为目前唯一的方法是使用overlay()
或ZStack
。使用overlay()
时我似乎无法进行转换,但使用ZStack
时我可以
只需确保您的模态视图使用List
或使用Spacer()
之类的内容填满屏幕,否则您仍然会看到它后面的另一个视图
struct ContentView: View
@State var showModal = false
let transition = AnyTransition.move(edge: .bottom)
var body: some View
ZStack
VStack
Button(action:
withAnimation
self.showModal = true
)
Text("Show Modal")
if self.showModal
ModalView()
.background(Color.white)
.transition(transition)
【讨论】:
【参考方案2】:
fullScreenCover()
修饰符
iOS 14 有一个名为 fullScreenCover()
的新 SwiftUI 修饰符。它是一种全屏模式的呈现方式。它的工作原理几乎与普通工作表相同。例如,这将在按下按钮时呈现全屏模式视图:
struct ContentView: View
Button("Present Full Screen Modal!")
self.isPresented.toggle()
.fullScreenCover(isPresented: $isPresented)
NavigationView
FullScreenModalView()
.toolbar
ToolbarItem(placement: .navigationBarTrailing)
Button(action:
isPresented = false
, label:
Text("Dismiss")
)
目标视图可以通过向下滑动或 Apple 推荐的更好的方式关闭,添加关闭按钮(已添加到导航工具栏中):
struct FullScreenModalView: View
var body: some View
ZStack
Color.pink
Text("This my full screen modal view")
.foregroundColor(.white)
.ignoresSafeArea()
.onTapGesture
presentationMode.wrappedValue.dismiss()
【讨论】:
【参考方案3】:简短的回答是,目前没有好的方法可以做到这一点。
这里有几个选择:
使用 UIKit + Swift 混合
看到这个Present a new view in SwiftUI
附加条件视图
第一个答案涵盖了这个解决方案。基本上,您使用Bool
在“基本”视图之上或代替“基本”视图呈现“模态”视图。
类似这样的:
struct ModalView: View
var closeAction: (() -> Void) =
var body: some View
ZStack
Color.blue.edgesIgnoringSafeArea(.all)
VStack
Text("I am a modal.")
.font(.largeTitle)
.fontWeight(.bold)
.foregroundColor(.white)
.padding()
Button(action:
self.closeAction()
, label:
Text("OK, BYE!")
.foregroundColor(.white)
.padding()
.overlay(
RoundedRectangle(cornerRadius: 5)
.stroke(Color.white, lineWidth: 1)
)
)
struct BaseView: View
@State private var showModal = false
var body: some View
ZStack
if showModal
ModalView(closeAction:
withAnimation(.easeOut(duration: 0.25)) self.showModal = false
).transition(.slideBottom)
else
VStack
Button(action:
withAnimation(.easeOut(duration: 0.25))
self.showModal = true
, label:
Text("Open Modal")
.padding()
.overlay(
RoundedRectangle(cornerRadius: 5)
.stroke(Color.blue, lineWidth: 1)
)
)
.statusBar(hidden: true)
它有自己的一系列问题:
不是真正的模态演示(?)。 “基本”视图及其所有视图层次结构仍然存在于“模态”下。如果您想支持可访问性,这可能会很痛苦。您当然可以呈现条件模式而不是在基础视图之上。此设置有效,但需要编写得相当巧妙才能很好地扩展。 您必须添加自己的动画过渡。 如果基础视图嵌入到 NavigationView 根目录中则不起作用,除非它的导航栏被隐藏 如果基础视图嵌入在 NavigationView 子视图中,则不起作用,即使用 NavigationLink 呈现的视图,除非其导航栏和后退按钮被隐藏 一般来说,当修饰符添加到给定布局中不是根视图的视图时,它不再是全屏模式。如需对此进行全面探索,请参阅 https://github.com/piterwilson/SwiftUI-Modal-on-iPad/tree/master/iPadConditionalViewModal 和此 ViewModifier
我让代码更简洁 https://github.com/piterwilson/SwiftUI-FullscreenModalViewModifier
使用NavigationView
+ NavigationLink
您也可以使用NavigationView
+ NavigationLink
全屏显示,但最大的问题是您将无法自定义动画。它看起来像这样:
struct ModalView: DismissableView
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
var body: some View
ZStack
Color.green.edgesIgnoringSafeArea(.all)
VStack
Text("I am a modal.")
.font(.largeTitle)
.fontWeight(.bold)
.foregroundColor(.white)
.padding()
Button(action:
self.dismiss()
, label:
Text("OK, BYE!")
.foregroundColor(.white)
.padding()
.overlay(
RoundedRectangle(cornerRadius: 5)
.stroke(Color.white, lineWidth: 1)
)
)
.navigationBarBackButtonHidden(true)
struct BaseView: View
var body: some View
NavigationView
VStack
NavigationLink(destination: ModalView())
Text("Open Modal")
.padding()
.overlay(
RoundedRectangle(cornerRadius: 5).stroke(Color.blue, lineWidth: 1)
)
.navigationViewStyle(StackNavigationViewStyle())
它也有问题:
动画不可自定义 不是真正的模态? (Modality的定义在这里https://developer.apple.com/design/human-interface-guidelines/ios/app-architecture/modality/)【讨论】:
以上是关于如何在 SwiftUI 中模态地推动下一个屏幕充满的主要内容,如果未能解决你的问题,请参考以下文章