UIKit的UIViewController向SwiftUI View传递绑定(Binding)

14

我正在尝试将SwiftUI View 在UIKit中使用。目前,我使用Binding<Bool>来关闭/展示 DetailView。以下是可用的代码:

struct ContentView: View {
    @State var presentingModal = false
    var body: some View {
        Button("Present") { self.presentingModal = true } /// tap button to present detail sheet
        .sheet(isPresented: $presentingModal) {
            DetailView(isPresentedBinding: $presentingModal) /// pass in the binding
        }
    }
}

struct DetailView: View {
    var isPresented: Binding<Bool>? /// it's an optional so I do this instead of `@Binding var isPresented: Bool`
    var body: some View {
        Button("Done") { isPresented?.wrappedValue = false } /// tap the "Done" button to dismiss
    }
}
当您按下“完成”按钮时,它会将isPresented设置为false,从而关闭该表。现在我想从UIViewController中呈现DetailView。这是我到目前为止的代码:
class ViewController: UIViewController {
    @IBAction func presentButtonPressed(_ sender: Any) {
        let detailViewController = DetailView_UIKit()
        self.present(detailViewController, animated: true, completion: nil)
    }
}

/// wrap DetailView in a ViewController so it's easier to present
class DetailView_UIKit: UIViewController {
    
    init() {
        super.init(nibName: nil, bundle: nil)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func loadView() {
        
        view = UIView()

        /// Host the `DetailView`
        let detailViewController = UIHostingController(
            rootView: DetailView() /// I need to pass a Binding in here!
        )
        
        self.addChild(detailViewController)
        view.addSubview(detailViewController.view)
        detailViewController.view.frame = view.bounds
        detailViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        detailViewController.didMove(toParent: self)
    }
    
    /// I want to call this function too
    func dismissThisViewController() {
        self.dismiss(animated: true, completion: nil)
    }
}

这个代码能够运行,但是“完成”按钮没有任何反应......Binding仍然为nil,因为我还没有将其分配给任何东西。我该如何在DetailView_UIKit内创建某种@State属性,以便我可以将其传递到DetailView中?当该属性设置为false时,我想调用dismissThisViewController。或者创建一个@State属性不是正确的方法,我不确定。

SwiftUI流程:

ContentView (present)→ DetailView
        ◟________________◞
             Binding

UIKit 流程:

ViewController (present)→ DetailView_UIKit → DetailView
                               ◟________________◞
                          Binding? Not sure what to put

感谢您的帮助!


这不是那样的...你不能通过SwiftUI绑定关闭使用present..方法呈现的UIKit控制器,你必须使用相应的UIKit dismiss...方法。 - Asperi
@Asperi 我知道,我只想让Binding调用dismiss方法。 - aheze
我添加了一些图示以澄清。 - aheze
1
绑定在SwiftUI视图之间起作用,ContentView是SwiftUI视图,DetailView_UIKit不是。 - Asperi
1个回答

14

事实证明在UIViewControllerView之间不能使用Binding

最后,我只是在DetailView中创建了一个可选闭包。

  • 如果我呈现DetailView_UIKit,我将为解除函数分配闭包,但不会传递Binding(无论如何都不行)。
  • 如果我直接呈现DetailView,我将像以前一样传递Binding,但不会分配闭包。

然后,当我按下DetailView内部的按钮时,我将尝试:

  1. Binding设置为false
  2. 调用闭包

顺序不重要,因为其中一个始终为nil。

DetailView:

struct DetailView: View {
    var isPresented: Binding<Bool>? /// Optional `Binding` from before

    var donePressed: (() -> Void)? /// The optional closure I just added

    var body: some View {
        Button("Done") {

            /// Attempt to set the `Binding` (dismiss the `.sheet` if SwiftUI)
            isPresented?.wrappedValue = false

            /// Attempt to call the closure (call the `self.dismiss` if UIKit)
            donePressed?()

        }
    }
}

DetailView_UIKit

override func loadView() {
    
    view = UIView()
    
    /// Host the `DetailView`
    let detailViewController = UIHostingController(
    rootView: DetailView() /// I DO NOT pass in a `Binding` here!
    )
    
    /// Assign the closure!
    detailViewController.donePressed = { [weak self] in
        self?.dismissThisViewController()
    }
    
    self.addChild(detailViewController)
    view.addSubview(detailViewController.view)
    detailViewController.view.frame = view.bounds
    detailViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    detailViewController.didMove(toParent: self)
}

/// Call this function in the closure
func dismissThisViewController() {
    self.dismiss(animated: true, completion: nil)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接