【发布时间】:2020-02-12 09:32:15
【问题描述】:
我有一个自定义的UIViewControllerRepresentable(与布局相关的代码如下所示)。这试图复制原生 SwiftUI ScrollView,除了它从底部滚动到顶部。
查看层次结构
view: UIView
|
\- scrollView: UIScrollView
|
\- innerView: UIView
|
\- hostingController.view: SwiftUI hosting view
当视图初始化时,这一切都按预期工作。托管视图填充了其内容,并且约束确保滚动视图的contentSize 设置正确。
但是,当托管视图的内容发生变化时,hostingController.view 不会调整大小以适应其内容。
绿色:正如预期的那样,滚动视图与宿主视图控制器的大小相匹配。
蓝色:托管视图本身。它保持第一次加载时的大小,并且不会按应有的方式扩展。
红色:托管视图中的堆栈视图。在此屏幕截图中,内容被添加到堆栈中,使其扩展。结果,您可以看到大小的差异。
UIHostingController(蓝色)应展开以适应其内容(红色)。
滚动视图的内容大小没有明确设置,因为这是由自动布局处理的。
约束代码如下所示,如果有帮助的话。
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()
}
}
【问题讨论】:
-
这个运气好吗?我自己也遇到过同样的问题。
-
在我自己的情况下,到目前为止,我最好的方法是只使用内置的 SwiftUI 可滚动对象之一(我想到了 List),而不是使用 UIScrollView 包装。我已经尝试过常规的 SwiftUI ScrollView,但这似乎与 Buttons 有问题。
-
我现在遇到了这个问题。在过去的几个月里,有人找到解决方案了吗?
-
@Rengers 刚刚针对一个非常相似的问题发布了我的解决方法,可能值得看看相同的方法是否适合您:stackoverflow.com/a/62263294/642233
标签: ios swift swiftui ios-autolayout uihostingcontroller