【问题标题】:Presenting View Controller in SwiftUI在 SwiftUI 中呈现视图控制器
【发布时间】:2020-06-25 08:15:50
【问题描述】:

如何使用 SwiftUI 实现以下 Objective-C 代码实现的功能?我无法牢牢把握所提出的想法。

    [self presentViewController:messageViewController animated:YES completion:nil];

【问题讨论】:

  • 你想找UIViewRepresentable,有很多教程展示了如何在SwiftUI中使用UIKit视图和视图控制器。
  • 我对这个问题的意义有点困惑。您想知道如何使用全屏显示任何视图吗?
  • @Kyokook 你是对的。我想知道如何在超级视图之上的屏幕中间呈现模态视图。

标签: view swiftui presentviewcontroller


【解决方案1】:

由于没有提供相关代码,所以伪代码如下所示

struct YourParentView: View {
   @State private var presented = false
   var body: some View {

      // some other code that activates `presented` state

      SomeUIElement()
         .sheet(isPresented: $presented) {
             YourMessageViewControllerRepresentable()
         }
   }
}

【讨论】:

  • 感谢您的回答。经过一番修补,它确实提高了我的理解。但是,我有一个后续问题:我已经阅读了一些关于 Representables 的内容,但它们似乎被设计为使用 UIViews。这也是在工作表中使用一些旧的 Objective C 视图的方法吗?换句话说,Representables 是否用于包装除 UIView 之外的其他视图,以便在执行特定操作时在超级视图之上呈现视图?
  • @Ali,可以表示精确的 UIView,当然包括所有子视图(通过 UIViewRepresentable)或整个 UIViewController(通过 UIViewControllerRepresentable)。如果您正确设置了 Objective-C/Swift 桥,那么您的 UIView/UIViewController 也可以正常工作 - 没有区别。
【解决方案2】:

在 ios 13.x 之前,SwiftUI 没有提供任何方法。由于我有同样的需求,写了一个自定义的View修饰符来实现。

extension View {
    func uiKitFullPresent<V: View>(isPresented: Binding<Bool>, style: UIModalPresentationStyle = .fullScreen, content: @escaping (_ dismissHandler: @escaping () -> Void) -> V) -> some View {
        self.modifier(FullScreenPresent(isPresented: isPresented, style: style, contentView: content))
    }
}

struct FullScreenPresent<V: View>: ViewModifier {
    @Binding var isPresented: Bool
    @State private var isAlreadyPresented: Bool = false
    
    let style: UIModalPresentationStyle
    let contentView: (_ dismissHandler: @escaping () -> Void) -> V
    
    @ViewBuilder
    func body(content: Content) -> some View {
        if isPresented {
            content
                .onAppear {
                    if self.isAlreadyPresented == false {
                        let hostingVC = UIHostingController(rootView: self.contentView({
                            self.isPresented = false
                            self.isAlreadyPresented = false
                            UIViewController.topMost?.dismiss(animated: true, completion: nil)
                        }))
                        hostingVC.modalPresentationStyle = self.style
                        UIViewController.topMost?.present(hostingVC, animated: true) {
                            self.isAlreadyPresented = true
                        }
                    }
                }
        } else {
            content
        }
    }
}

而且,你可以像下面这样使用它。

.uiKitFullPresent(isPresented: $isShowingPicker, content: { closeHandler in
    SomeFullScreenView()
        .onClose(closeHandler) // '.onClose' is a custom extension function written. you can invent your own way to call 'closeHandler'.
})

.uiKitFullPresent 的content 参数是一个以回调处理程序作为其参数的闭包。您可以使用此回调来关闭呈现的视图。

到目前为止,它运行良好。不过看起来有点棘手。

您可能知道,iOS 14 将为我们带来一种以您想要的方式呈现任何视图的方法。签出fullScreenCover()。

关于呈现由Objective-C编写的UIViewController,正如Asperi在他的帖子中提到的那样。

更新
这是我目前使用的完整源代码。 https://gist.github.com/fullc0de/3d68b6b871f20630b981c7b4d51c8373

【讨论】:

    【解决方案3】:

    试试吧:

    struct YourParentView: View {
       @State private var presented = false
       var body: some View {
    
          // some other code that activates `presented` state
    
          SomeUIElement()
             .sheet(isPresented: $showingSheet, onDismiss: {
                 presented = false
             }, content: {
                 YourMessageViewControllerRepresentable() //Needs to be UIViewRepresentable()
             }
       }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-07-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多