繁体   English   中英

在 SwiftUI 中呈现新视图

[英]Present a new view in SwiftUI

我想单击一个按钮,然后在 UIKit 中以present modally方式呈现一个新视图在此处输入图像描述

我已经看过“ 如何使用工作表呈现新视图”,但我不想将其作为模式工作表附加到主视图。

而且我不想使用NavigationLink ,因为我不希望新视图和旧视图有导航关系。

谢谢你的帮助...

显示模式(iOS 13 风格)

您只需要一张能够自行关闭的简单sheet

struct ModalView: View {
    @Binding var presentedAsModal: Bool
    var body: some View {
        Button("dismiss") { self.presentedAsModal = false }
    }
}

并将其呈现为:

struct ContentView: View {
    @State var presentingModal = false
    
    var body: some View {
        Button("Present") { self.presentingModal = true }
        .sheet(isPresented: $presentingModal) { ModalView(presentedAsModal: self.$presentingModal) }
    }
}

请注意,我将presentingModal传递给模态,因此您可以将其从模态本身中消除,但您可以摆脱它。


让它真正呈现fullscreen (不仅仅是视觉上)

您需要访问ViewController 所以你需要一些辅助容器和环境的东西:

struct ViewControllerHolder {
    weak var value: UIViewController?
}

struct ViewControllerKey: EnvironmentKey {
    static var defaultValue: ViewControllerHolder {
        return ViewControllerHolder(value: UIApplication.shared.windows.first?.rootViewController)

    }
}

extension EnvironmentValues {
    var viewController: UIViewController? {
        get { return self[ViewControllerKey.self].value }
        set { self[ViewControllerKey.self].value = newValue }
    }
}

然后你应该使用实现这个扩展:

extension UIViewController {
    func present<Content: View>(style: UIModalPresentationStyle = .automatic, @ViewBuilder builder: () -> Content) {
        let toPresent = UIHostingController(rootView: AnyView(EmptyView()))
        toPresent.modalPresentationStyle = style
        toPresent.rootView = AnyView(
            builder()
                .environment(\.viewController, toPresent)
        )
        NotificationCenter.default.addObserver(forName: Notification.Name(rawValue: "dismissModal"), object: nil, queue: nil) { [weak toPresent] _ in
            toPresent?.dismiss(animated: true, completion: nil)
        }
        self.present(toPresent, animated: true, completion: nil)
    }
}

最后

你可以让它fullscreen像:

struct ContentView: View {
    @Environment(\.viewController) private var viewControllerHolder: UIViewController?
    
    var body: some View {
        Button("Login") {
            self.viewControllerHolder?.present(style: .fullScreen) {
                Text("Main") // Or any other view you like
// uncomment and add the below button for dismissing the modal
            // Button("Cancel") {
            //       NotificationCenter.default.post(name: Notification.Name(rawValue: "dismissModal"), object: nil)
            //        }
            }
        }
    }
}

对于 iOS 14 和 Xcode 12:

struct ContentView: View {
    @State private var isPresented = false

var body: some View {
    Button("Show Modal with full screen") {
        self.isPresented.toggle()
    }
    .fullScreenCover(isPresented: $isPresented, content: FullScreenModalView.init)
    }
}
struct FullScreenModalView: View {
     @Environment(\.presentationMode) var presentationMode

var body: some View {
    VStack {
        Text("This is a modal view")
    }
    .frame(maxWidth: .infinity, maxHeight: .infinity)
    .background(Color.red)
    .edgesIgnoringSafeArea(.all)
    .onTapGesture {
        presentationMode.wrappedValue.dismiss()
    }
}
}

希望这个答案可以帮助到大家。 在下面评论您的结果。

参考: 此链接

免责声明:下面并不是真正的“本机模式”,既不是行为也不是外观和感觉,但如果有人需要一个视图的自定义转换,只激活顶部视图,以下方法可能会有所帮助。

因此,如果您期望以下内容

自定义 SwiftUI 模态

这是演示方法的简单代码(可根据需要更改 animation 和转换参数)

struct ModalView : View {
    @Binding var activeModal: Bool
    var body : some View {
        VStack {
            Button(action: {
                withAnimation(.easeInOut(duration: 0.3)) {
                    self.activeModal = false
                }
            }) {
                Text("Hide modal")
            }
            Text("Modal View")
        }
        .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center)
        .background(Color.green)
    }
}

struct MainView : View {
    @Binding var activeModal: Bool
    var body : some View {
        VStack {
            Button(action: {
                withAnimation(.easeInOut(duration: 0.3)) {
                    self.activeModal = true
                }
            }) {
                Text("Show modal")
            }
            Text("Main View")
        }
        .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center)
        .background(Color.yellow)
    }
}

struct ModalContainer: View {
    @State var showingModal = false
    var body: some View {
        ZStack {
            MainView(activeModal: $showingModal)
                .allowsHitTesting(!showingModal)
                .disabled(showingModal)
            if showingModal {
                ModalView(activeModal: $showingModal)
                    .transition(.move(edge: .bottom))
                    .zIndex(1)
            }
        }
    }
}

备份

这是一种简单的方法——前瞻观点。 这是非常直接的。

        struct ChildView: View{
           private  let colors: [Color] = [.red, .yellow,.green,.white]
           @Binding var index : Int
           var body: some View {
           let next = (self.index+1)  % MyContainer.totalChildren
             return   ZStack{
                    colors[self.index  % colors.count]
                     Button("myNextView \(next)   ", action: {
                    withAnimation{
                        self.index = next
                    }
                    }
                )}.transition(.asymmetric(insertion: .move(edge: .trailing)  , removal:  .move(edge: .leading)  ))
            }
        }

        struct MyContainer: View {
            static var totalChildren = 10
            @State private var value: Int = 0
            var body: some View {
                    HStack{
                        ForEach(0..<(Self.totalChildren) ) { index in
                            Group{
                            if    index == self.value {
                                ChildView(index:  self.$value)
                                }}
                            }
                }
                }
        }

然后在点击按钮时从 ContentView 呈现它:

struct SheetView: View {
        @Environment(\.dismiss) var dismiss
    
        var body: some View {
            Button("Press to dismiss") {
                dismiss()
            }
            .font(.title)
            .padding()
            .background(Color.black)
        }
    }
    
    struct ContentView: View {
        @State private var showingSheet = false
    
        var body: some View {
            Button("Show Sheet") {
                showingSheet.toggle()
            }
            .sheet(isPresented: $showingSheet) {
                SheetView()
            }
        }
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM