SwiftUI-具有全屏模式的PresentationButton

Man*_*ero 17 swiftui xcode11

我正在尝试实现一个按钮,该按钮使用“来自Botton的幻灯片”动画呈现另一个场景。

PresentationButton看起来不错,因此我尝试了一下:

import SwiftUI

struct ContentView : View {
    var body: some View {
        NavigationView {
            PresentationButton(destination: Green().frame(width: 1000.0)) {
                Text("Click")

                }.navigationBarTitle(Text("Navigation"))
        }
    }
}

#if DEBUG
struct ContentView_Previews : PreviewProvider {
    static var previews: some View {
        Group {
            ContentView()
                .previewDevice("iPhone X")
                .colorScheme(.dark)

            ContentView()
                .colorScheme(.dark)
                .previewDevice("iPad Pro (12.9-inch) (3rd generation)"

            )

        }

    }
}
#endif
Run Code Online (Sandbox Code Playgroud)

结果如下: 在此处输入图片说明

我希望绿色视图能够覆盖整个屏幕,并且还希望模式不能“拖动以关闭”。

是否可以在PresentationButton中添加修饰符以使其全屏显示并且不可拖动?

我也尝试过导航按钮,但是:-它不会“从底部滑动”-它在详细信息视图上创建了“后退按钮”,我不希望这样

谢谢!

小智 10

Xcode 12.0 - SwiftUI 2 - iOS 14

现在可能。使用 fullScreenCover() 修饰符。

var body: some View {
    Button("Present!") {
        self.isPresented.toggle()
    }
    .fullScreenCover(isPresented: $isPresented, content: FullScreenModalView.init)
}
Run Code Online (Sandbox Code Playgroud)

使用 Swift 进行黑客攻击


ars*_*ius 9

不幸的是,截至 Beta 2Beta 3,这在纯SwiftUI中是不可能的。你可以看到,Modal 没有参数的像什么UIModalPresentationStyle.fullScreen。对于PresentationButton也是如此

我建议提起雷达。

您当前可以执行的最接近的操作是:

    @State var showModal: Bool = false
    var body: some View {
        NavigationView {
            Button(action: {
                self.showModal = true
            }) {
                Text("Tap me!")
            }
        }
        .navigationBarTitle(Text("Navigation!"))
        .overlay(self.showModal ? Color.green : nil)
    }
Run Code Online (Sandbox Code Playgroud)

当然,您可以从那里在叠加层中添加所需的任何过渡效果。


ars*_*ius 9

尽管我的其他答案目前是正确的,但人们现在可能希望能够做到这一点。我们可以使用将Environment视图控制器传递给子级。 要点在这里

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: UIViewControllerHolder {
        get { return self[ViewControllerKey.self] }
        set { self[ViewControllerKey.self] = newValue }
    }
}
Run Code Online (Sandbox Code Playgroud)

向UIViewController添加扩展

extension UIViewController {
    func present<Content: View>(style: UIModalPresentationStyle = .automatic, @ViewBuilder builder: () -> Content) {
       // Must instantiate HostingController with some sort of view...
        let toPresent = UIHostingController(rootView: AnyView(EmptyView()))
       ... but then we can reset that view to include the environment
        toPresent.rootView = AnyView(
            builder()
                .environment(\.viewController, ViewControllerHolder(value: toPresent))
        )
        self.present(toPresent, animated: true, completion: nil)
    }
}
Run Code Online (Sandbox Code Playgroud)

并在需要时使用它:

struct MyView: View {

    @Environment(\.viewController) private var viewControllerHolder: UIViewController?
    private var viewController: UIViewController? {
        self.viewControllerHolder.value
    }

    var body: some View {
        Button(action: {
           self.viewController?.present(style: .fullScreen) {
              MyView()
           }
        }) {
           Text("Present me!")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

[编辑]尽管最好这样做,这样@Environment(\.viewController) var viewController: UIViewController?会导致保留周期。因此,您需要使用支架。

  • 我建议在“扩展”的“当前”功能内添加“ toPresent.modalPresentationStyle = style”,以使新显示的屏幕实际上全屏显示 (2认同)