在SwiftUI中呈现视图控制器

12
如何使用SwiftUI实现以下Objective-C代码所实现的功能?我无法完全掌握所提出的思想。
如上内容翻译后为:

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

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

如果你想寻找 UIViewRepresentable,有很多教程展示了如何在 SwiftUI 中使用 UIKit 视图和视图控制器。 - Andrew
我有点困惑这个问题的重点是什么。您想知道如何将任何视图呈现为全屏吗? - Kyokook Hwang
@Kyokook 你说得对。我想知道如何在父视图上方的屏幕中央呈现模态视图。 - user12919782
2个回答

10

在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'.
})
.uiKitFullPresentcontent参数是一个闭包,它有一个回调处理程序作为其参数。您可以使用此回调来关闭呈现的视图。
到目前为止,它一直表现良好。不过看起来有点棘手。
正如您所知,iOS 14将为我们带来以任何您想要的方式呈现任何视图的方法。请查看fullScreenCover()
关于呈现由Objective-C编写的UIViewController,正如Asperi在他的博客中提到的那样,这是可能的。
更新: 这是我目前正在使用的完整源代码。 https://gist.github.com/fullc0de/3d68b6b871f20630b981c7b4d51c8373 更新2: 现在,我想说这不是一个好的方法,因为潜在的思路似乎与SwiftUI机制并不匹配。

9
由于没有提供相关的代码,因此在伪代码中,它看起来像是这样:
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的内容,但它们似乎是设计用于使用UIView。这也是在sheet中使用一些旧的Objective C View的方式吗?换句话说,Representables是否用于包装除UIView以外的其他视图,以在执行特定操作时在父视图上方呈现视图? - user12919782
1
@Ali,可以通过UIViewRepresentable来表示精确的UIView,当然包括所有的子视图;或者通过UIViewControllerRepresentable来表示整个UIViewController。如果你正确地设置了Objective-C/Swift桥接,那么你的UIView/UIViewController也将正常工作 - 没有任何区别。 - Asperi

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