UIViewControllerRepresentable 当前仅在 iOS 14 中不更新
UIViewControllerRepresentable doesn't update currently only in iOS 14
我创建了 UIViewControllerRepresentable 来呈现弹出窗口。
我确实在 Xcode 13 和 iOS 15 上测试过它作为视频在 link
上效果很好
但它在 Xcode 12.5.1 和 iOS 14.8 上无法像预期的那样工作 link
我不知道为什么它在 iOS 14.8 上不起作用,是否有其他解决方案可以使其在两个 iOS 版本上都起作用?
我的代码:
struct PopoverViewModifier<PopoverContent>: ViewModifier where PopoverContent: View {
@Binding var isPresented: Bool
let onDismiss: (() -> Void)?
let content: () -> PopoverContent
func body(content: Content) -> some View {
content
.background(
Popover(
isPresented: self.$isPresented,
onDismiss: self.onDismiss,
content: self.content
)
)
}
}
extension View {
func cocoaPopover<Content>(
isPresented: Binding<Bool>,
onDismiss: (() -> Void)? = nil,
content: @escaping () -> Content
) -> some View where Content: View {
ModifiedContent(
content: self,
modifier: PopoverViewModifier(
isPresented: isPresented,
onDismiss: onDismiss,
content: content
)
)
}
}
struct Popover<Content: View> : UIViewControllerRepresentable {
@Binding var isPresented: Bool
let onDismiss: (() -> Void)?
@ViewBuilder let content: () -> Content
func makeCoordinator() -> Coordinator {
return Coordinator(parent: self, content: self.content())
}
func makeUIViewController(context: Context) -> UIViewController {
return UIViewController()
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
let host = context.coordinator.host
host.rootView = content()
if host.viewIfLoaded?.window == nil && self.isPresented {
host.preferredContentSize = host.sizeThatFits(in: CGSize(width: Int.max , height: Int.max))
host.modalPresentationStyle = UIModalPresentationStyle.popover
host.popoverPresentationController?.delegate = context.coordinator
host.popoverPresentationController?.sourceView = uiViewController.view
host.popoverPresentationController?.sourceRect = uiViewController.view.bounds
uiViewController.present(host, animated: true, completion: nil)
} else if self.isPresented == false {
host.dismiss(animated: false, completion: nil)
}
}
class Coordinator: NSObject, UIPopoverPresentationControllerDelegate {
let host: UIHostingController<Content>
private let parent: Popover
init(parent: Popover, content: Content) {
self.parent = parent
self.host = UIHostingController(rootView: content)
}
func presentationControllerWillDismiss(_ presentationController: UIPresentationController) {
self.parent.isPresented = false
if let onDismiss = self.parent.onDismiss {
onDismiss()
}
}
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}
}
}
您的问题与代表无关。 iOS14 及其处理工具栏按钮的方式似乎存在错误。当您在工具栏中放置一个按钮时,它的几何行为有点奇怪(iOS14)。 运行 以下代码并检查两个 iOS 版本的结果。
struct ContentView: View {
@State var show = false
var body: some View {
NavigationView {
VStack {
Text("Hello, world!")
}
.toolbar {
Button("Show") {
show = true
}
.border(Color.green)
}
}
}
}
在 iOS 15,它看起来像这样:
但是在 iOS 14 上,它看起来像这样:
那么绿色边框是怎么回事?任何放置在边框、叠加层或背景中的东西都会被绘制到其他地方(就我目前所见,在屏幕之外)。
请注意,此问题仅发生在工具栏内的按钮。
这种糟糕的几何结构会直接影响您的弹出窗口。因此,如果我们找到修复该几何形状的方法,您的弹出窗口的问题也会消失。我可以想到两个解决方法:
- 用可点击的文本替换您的按钮:
Text("Show").onTapGesture { ... }
这可行,但如果您想模拟真实按钮的外观,则需要做更多的工作。幸运的是,有 2 号解决方法。
- 使用透明文本作为工具栏项目,并将按钮放在它上面:
struct ContentViewx: View {
@State var show = false
var body: some View {
NavigationView {
VStack {
Text("Hello, world!")
}
.toolbar {
Text("Show")
.opacity(0)
.overlay(
Button("Show") {
show = true
}
)
.cocoaPopover(isPresented: $show) {
print("dismiss!")
} content: {
Text("Hello, this is the popover!")
}
}
}
}
}
我创建了 UIViewControllerRepresentable 来呈现弹出窗口。
我确实在 Xcode 13 和 iOS 15 上测试过它作为视频在 link
上效果很好但它在 Xcode 12.5.1 和 iOS 14.8 上无法像预期的那样工作 link
我不知道为什么它在 iOS 14.8 上不起作用,是否有其他解决方案可以使其在两个 iOS 版本上都起作用?
我的代码:
struct PopoverViewModifier<PopoverContent>: ViewModifier where PopoverContent: View {
@Binding var isPresented: Bool
let onDismiss: (() -> Void)?
let content: () -> PopoverContent
func body(content: Content) -> some View {
content
.background(
Popover(
isPresented: self.$isPresented,
onDismiss: self.onDismiss,
content: self.content
)
)
}
}
extension View {
func cocoaPopover<Content>(
isPresented: Binding<Bool>,
onDismiss: (() -> Void)? = nil,
content: @escaping () -> Content
) -> some View where Content: View {
ModifiedContent(
content: self,
modifier: PopoverViewModifier(
isPresented: isPresented,
onDismiss: onDismiss,
content: content
)
)
}
}
struct Popover<Content: View> : UIViewControllerRepresentable {
@Binding var isPresented: Bool
let onDismiss: (() -> Void)?
@ViewBuilder let content: () -> Content
func makeCoordinator() -> Coordinator {
return Coordinator(parent: self, content: self.content())
}
func makeUIViewController(context: Context) -> UIViewController {
return UIViewController()
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
let host = context.coordinator.host
host.rootView = content()
if host.viewIfLoaded?.window == nil && self.isPresented {
host.preferredContentSize = host.sizeThatFits(in: CGSize(width: Int.max , height: Int.max))
host.modalPresentationStyle = UIModalPresentationStyle.popover
host.popoverPresentationController?.delegate = context.coordinator
host.popoverPresentationController?.sourceView = uiViewController.view
host.popoverPresentationController?.sourceRect = uiViewController.view.bounds
uiViewController.present(host, animated: true, completion: nil)
} else if self.isPresented == false {
host.dismiss(animated: false, completion: nil)
}
}
class Coordinator: NSObject, UIPopoverPresentationControllerDelegate {
let host: UIHostingController<Content>
private let parent: Popover
init(parent: Popover, content: Content) {
self.parent = parent
self.host = UIHostingController(rootView: content)
}
func presentationControllerWillDismiss(_ presentationController: UIPresentationController) {
self.parent.isPresented = false
if let onDismiss = self.parent.onDismiss {
onDismiss()
}
}
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}
}
}
您的问题与代表无关。 iOS14 及其处理工具栏按钮的方式似乎存在错误。当您在工具栏中放置一个按钮时,它的几何行为有点奇怪(iOS14)。 运行 以下代码并检查两个 iOS 版本的结果。
struct ContentView: View {
@State var show = false
var body: some View {
NavigationView {
VStack {
Text("Hello, world!")
}
.toolbar {
Button("Show") {
show = true
}
.border(Color.green)
}
}
}
}
在 iOS 15,它看起来像这样:
但是在 iOS 14 上,它看起来像这样:
那么绿色边框是怎么回事?任何放置在边框、叠加层或背景中的东西都会被绘制到其他地方(就我目前所见,在屏幕之外)。
请注意,此问题仅发生在工具栏内的按钮。
这种糟糕的几何结构会直接影响您的弹出窗口。因此,如果我们找到修复该几何形状的方法,您的弹出窗口的问题也会消失。我可以想到两个解决方法:
- 用可点击的文本替换您的按钮:
Text("Show").onTapGesture { ... }
这可行,但如果您想模拟真实按钮的外观,则需要做更多的工作。幸运的是,有 2 号解决方法。
- 使用透明文本作为工具栏项目,并将按钮放在它上面:
struct ContentViewx: View {
@State var show = false
var body: some View {
NavigationView {
VStack {
Text("Hello, world!")
}
.toolbar {
Text("Show")
.opacity(0)
.overlay(
Button("Show") {
show = true
}
)
.cocoaPopover(isPresented: $show) {
print("dismiss!")
} content: {
Text("Hello, this is the popover!")
}
}
}
}
}