UIScrollView动态修改contentSize点击按钮后不生效如何解决
问题原因
现有代码存在三个核心问题导致更新不生效:
- 修改内部元素尺寸后没有主动触发布局更新,遍历读取到的
frame还是修改前的旧值 - 遍历所有
subviews时把UIScrollView自带的垂直/水平滚动指示器也纳入了计算范围,计算结果不可靠,之前生效只是巧合 contentSize赋值放在了for循环内部,每次遍历一个子视图就赋值一次,属于无效操作
修复方案
方案1:手动计算contentSize(适配frame布局场景)
先强制刷新布局拿到最新的子视图尺寸,过滤掉系统滚动指示器后再计算统一赋值,修复后代码如下:
DispatchQueue.main.async { // 强制立刻更新布局,拿到子视图修改后的最新frame self.scrollView.layoutIfNeeded() var contentRect = CGRect.zero for view in self.scrollView.subviews { // 跳过系统自带的滚动指示器视图,避免干扰计算结果 guard !NSStringFromClass(type(of: view)).contains("ScrollIndicator") else { continue } contentRect = contentRect.union(view.frame) } // 遍历完成后统一赋值contentSize self.scrollView.contentSize = contentRect.size }
更稳妥的优化方案:初始化时给UIScrollView加一个统一的内容容器contentView,所有内部元素都添加到这个contentView上,后续不需要遍历所有子视图,直接取容器尺寸即可:
// 初始化时只需要执行一次 let contentView = UIView() scrollView.addSubview(contentView) // 更新contentSize的代码 DispatchQueue.main.async { self.scrollView.layoutIfNeeded() self.scrollView.contentSize = self.contentView.bounds.size }
方案2:AutoLayout自动适配(推荐)
如果你的项目用AutoLayout布局,完全不需要手动计算contentSize,只需要给容器视图加对约束即可自动适配:
contentView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ // 容器四边和scrollView的内容布局 guide 绑定 contentView.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor), contentView.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor), contentView.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor), contentView.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor), // 垂直滚动场景:固定容器宽度和scrollView可视区域宽度一致 contentView.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor) // 水平滚动场景替换为固定高度: // contentView.heightAnchor.constraint(equalTo: scrollView.frameLayoutGuide.heightAnchor) ])
配置完成后,修改内部元素的尺寸或约束后,只需要调用view.layoutIfNeeded()触发布局更新,系统会自动计算并更新contentSize,不需要手动赋值。
内容的提问来源于stack exchange,提问作者alex ananchenko
相关产品推荐
相关产品推荐

