swift - UIViewControllerRepresentable 目前仅在 iOS 14 中不更新
问题描述
我创建了 UIViewControllerRepresentable 来呈现弹出框。
我确实在 Xcode 13 和 iOS 15 上对其进行了测试,它在此链接上的视频效果很好
但它在 Xcode 12.5.1 和 iOS 14.8 上无法按预期工作作为此链接上的视频
我不知道为什么它不能在 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 { ... }
这行得通,但如果你想模拟真实按钮的外观,你需要做更多的工作。幸运的是,有第二个解决方法。
- 使用透明的 Text 作为工具栏项,并将按钮放在它上面:
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!")
}
}
}
}
}
推荐阅读
- java - 从 servlet 向 html 页面发送警报
- tensorflow - 我们可以将所有数据集用于 doc2vec 和 CNN 吗?
- javascript - 使用 csv-parser 节点模块时的意外行为
- amazon-web-services - 在 Cognito 中有一种从特定用户的角度登录的方法
- python - 使用 selenium 登录linkedin
- javascript - net::ERR_ABORTED 404(未找到) - 控制台错误
- javascript - 当 package.json 位于其他位置时,从根目录执行 npm 任务
- azure-devops - 如何在为所有人发布之前测试新的 Azure DevOps 扩展版本
- python - 如何从python中的列表列表中获取唯一的组合值
- c# - 非静态方法需要一个目标;使用实体框架