如何在 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 中模态地推动下一个屏幕充满的主要内容,如果未能解决你的问题,请参考以下文章

模态segue推动顶部的附加导航栏滑动

在 Swiftui 中如何通过旋转到横向自动关闭模态

如何检测模态视图在 SwiftUI 中全局可见

如何在 SwiftUI 中制作具有透明背景的模态视图?

UIAlertController通过模态视图控制器向上和向下推动

如何使用 SwiftUI 在模态视图中创建 NSManagedObject?