在 SwiftUI 中呈现视图控制器
Presenting View Controller in SwiftUI
下面Objective-C代码用SwiftUI实现的功能如何实现?我一直无法牢牢掌握所提出的想法。
[self presentViewController:messageViewController animated:YES completion:nil];
由于没有提供相关代码,所以伪代码如下
struct YourParentView: View {
@State private var presented = false
var body: some View {
// some other code that activates `presented` state
SomeUIElement()
.sheet(isPresented: $presented) {
YourMessageViewControllerRepresentable()
}
}
}
直到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'.
})
content
.uiKitFullPresent
的参数是一个以回调处理程序作为参数的闭包。您可以使用此回调关闭呈现的视图。
到目前为止效果很好。不过看起来有点棘手。
如您所知,iOS14 将为我们带来一种以您想要的方式呈现任何视图的方法。检查 fullScreenCover()
。
关于呈现由 Objective-C 编写的 UIViewController,正如 Asperi 在他的 post 中提到的那样是可能的。
更新
这是我目前使用的完整源代码。
https://gist.github.com/fullc0de/3d68b6b871f20630b981c7b4d51c8373
UPDATE_2
现在,我想说这不是一个好方法,因为底层的想法实际上似乎与 SwiftUI 的机制不太匹配。
下面Objective-C代码用SwiftUI实现的功能如何实现?我一直无法牢牢掌握所提出的想法。
[self presentViewController:messageViewController animated:YES completion:nil];
由于没有提供相关代码,所以伪代码如下
struct YourParentView: View {
@State private var presented = false
var body: some View {
// some other code that activates `presented` state
SomeUIElement()
.sheet(isPresented: $presented) {
YourMessageViewControllerRepresentable()
}
}
}
直到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'.
})
content
.uiKitFullPresent
的参数是一个以回调处理程序作为参数的闭包。您可以使用此回调关闭呈现的视图。
到目前为止效果很好。不过看起来有点棘手。
如您所知,iOS14 将为我们带来一种以您想要的方式呈现任何视图的方法。检查 fullScreenCover()
。
关于呈现由 Objective-C 编写的 UIViewController,正如 Asperi 在他的 post 中提到的那样是可能的。
更新
这是我目前使用的完整源代码。
https://gist.github.com/fullc0de/3d68b6b871f20630b981c7b4d51c8373
UPDATE_2
现在,我想说这不是一个好方法,因为底层的想法实际上似乎与 SwiftUI 的机制不太匹配。