SwiftUI - PresentationButton with modal that is full screen

后端 未结 6 2090
滥情空心
滥情空心 2020-12-08 10:18

I am trying to implement a button that presents another scene with a \"Slide from Botton\" animation.

PresentationButton looked like a good candidate, so I gave it

6条回答
  •  孤城傲影
    2020-12-08 10:53

    Although my other answer is currently correct, people probably want to be able to do this now. We can use the Environment to pass a view controller to children. Gist here

    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 }
        }
    }
    

    Add an extension to UIViewController

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

    And whenever we need it, use it:

    struct MyView: View {
    
        @Environment(\.viewController) private var viewControllerHolder: ViewControllerHolder
        private var viewController: UIViewController? {
            self.viewControllerHolder.value
        }
    
        var body: some View {
            Button(action: {
               self.viewController?.present(style: .fullScreen) {
                  MyView()
               }
            }) {
               Text("Present me!")
            }
        }
    }
    

    [EDIT] Although it would be preferable to do something like @Environment(\.viewController) var viewController: UIViewController? this leads to a retain cycle. Therefore, you need to use the holder.

提交回复
热议问题