在 SwiftUI 中呈现视图控制器
Posted
技术标签:
【中文标题】在 SwiftUI 中呈现视图控制器【英文标题】:Presenting View Controller in SwiftUI 【发布时间】:2020-06-25 08:15:50 【问题描述】:如何使用 SwiftUI 实现以下 Objective-C 代码实现的功能?我无法牢牢把握所提出的想法。
[self presentViewController:messageViewController animated:YES completion:nil];
【问题讨论】:
你想找UIViewRepresentable
,有很多教程展示了如何在SwiftUI中使用UIKit视图和视图控制器。
我对这个问题的意义有点困惑。您想知道如何使用全屏显示任何视图吗?
@Kyokook 你是对的。我想知道如何在超级视图之上的屏幕中间呈现模态视图。
【参考方案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()
【讨论】:
以上是关于在 SwiftUI 中呈现视图控制器的主要内容,如果未能解决你的问题,请参考以下文章
在视图外触发时如何绑定 SwiftUI.Alert 的呈现?