gpt4 book ai didi

ios - UIHostingController 应该扩展以适应内容

转载 作者:行者123 更新时间:2023-12-01 10:18:15 27 4
gpt4 key购买 nike

我有一个自定义 UIViewControllerRepresentable (布局相关代码如下所示)。这试图复制原生 SwiftUI ScrollView , 除了它从顶部以外的底部滚动。
查看层次结构

view: UIView
|
\- scrollView: UIScrollView
|
\- innerView: UIView
|
\- hostingController.view: SwiftUI hosting view
当 View 初始化时,这一切都按预期工作。宿主视图填充了它的内容,并且约束确保 ScrollView 的 contentSize设置正确。
然而,当宿主视图的内容改变时, hostingController.view不会调整大小以适应其内容。
Screenshot of UI capture from app in Xcode. Shows contents of hosting controller expanding behind the bounds of the hosting view itself, without properly resizing.

Green: As intended, the scroll view matches the size of the hosting view controller.

Blue: The hosting view itself. It keeps the size it had when it was first loaded, and doesn't expend as it should.

Red: A stack view within the hosting view. In this screenshot, content was been added to the stack, causing it to expand. You can see the difference in size as a result.


UIHostingController(蓝色)应该扩展以适应其内容(红色)。
ScrollView 的内容大小没有明确设置,因为这是由自动布局处理的。
如果有帮助,约束代码如下所示。
class UIBottomScrollViewController<Content: View>: UIViewController, UIScrollViewDelegate {
var hostingController: UIHostingController<Content>! = nil

init(rootView: Content) {
self.hostingController = UIHostingController<Content>(rootView: rootView)
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

var scrollView: UIScrollView = UIScrollView()
var innerView = UIView()

override func loadView() {
self.view = UIView()
self.addChild(hostingController)
view.addSubview(scrollView)
scrollView.addSubview(innerView)
innerView.addSubview(hostingController.view)

scrollView.delegate = self
scrollView.scrollsToTop = true
scrollView.isScrollEnabled = true
scrollView.clipsToBounds = false

scrollView.layoutMargins = .zero
scrollView.preservesSuperviewLayoutMargins = true

scrollView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
scrollView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true

innerView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
innerView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
innerView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
innerView.leftAnchor.constraint(equalTo: scrollView.leftAnchor).isActive = true
innerView.rightAnchor.constraint(equalTo: scrollView.rightAnchor).isActive = true
innerView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true


hostingController.view.topAnchor.constraint(equalTo: innerView.topAnchor).isActive = true
hostingController.view.leftAnchor.constraint(equalTo: innerView.leftAnchor).isActive = true
hostingController.view.rightAnchor.constraint(equalTo: innerView.rightAnchor).isActive = true
hostingController.view.bottomAnchor.constraint(equalTo: innerView.bottomAnchor).isActive = true


hostingController.view.autoresizingMask = []
hostingController.view.layoutMargins = .zero
hostingController.view.insetsLayoutMarginsFromSafeArea = false
hostingController.view.translatesAutoresizingMaskIntoConstraints = false

scrollView.autoresizingMask = []
scrollView.layoutMargins = .zero
scrollView.insetsLayoutMarginsFromSafeArea = false
scrollView.translatesAutoresizingMaskIntoConstraints = false

innerView.autoresizingMask = []
innerView.layoutMargins = .zero
innerView.insetsLayoutMarginsFromSafeArea = false
innerView.translatesAutoresizingMaskIntoConstraints = false

hostingController.didMove(toParent: self)

scrollView.keyboardDismissMode = .interactive
}
}

struct BottomScrollView<Content: View>: UIViewControllerRepresentable {
var content: () -> Content

init(@ViewBuilder content: @escaping () -> Content) {
self.content = content
}

func makeUIViewController(context: Context) -> UIBottomScrollViewController<Content> {
let vc = UIBottomScrollViewController(rootView: self.content())
return vc
}
func updateUIViewController(_ viewController: UIBottomScrollViewController<Content>, context: Context) {
viewController.hostingController.rootView = self.content()
}
}

最佳答案

对我来说,这个解决方案比我在这里看到的任何其他答案都简单得多(没有一个有效),尽管我花了很长时间才找到它。
我所做的只是创建一个UIHostingController 的瘦子类。调用 invalidateIntrinsicContentSize()viewDidLayoutSubviews() 的回应

class SelfSizingHostingController<Content>: UIHostingController<Content> where Content: View {

override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.view.invalidateIntrinsicContentSize()
}
}
与原始问题类似,我在 UIViewController 中托管了一个 SwiftUI View 。在 UIScrollView ,需要与滚动内容 View 中的其他 View 一起布局。 SwiftUI View 的固有大小根据其内容和用户选择的动态类型大小而变化。
就我而言,这真的很简单。它适用于 iOS 14+(未在 iOS 13 上测试),其中 SwiftUI 内容的更改会导致新的内在大小正确更新 ScrollView 中基于自动布局的 UIKit 布局。老实说,这不是 UIHostingController 的隐含行为,这感觉就像一个错误。 .

关于ios - UIHostingController 应该扩展以适应内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58399123/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com