UIScrollView内添加/展开动画引发异常滚动问题求助
UIScrollView添加展开动画时异常滚动的原因及解决方法
问题原因
当UIScrollView进入可滚动状态后,添加视图并执行展开动画的过程中,系统会自动调整contentOffset以试图让新内容保持可见,从而引发异常滚动:
- 第一步添加高度为0的隐藏视图并执行
layoutIfNeeded时,UIScrollView的contentSize发生微小变化,系统会临时调整滚动偏移; - 第二步取消隐藏视图的高度约束并执行动画布局时,
contentSize大幅增加,系统再次调整偏移以适配新高度,两次调整叠加就造成了先向下再向上的滚动跳动。
此外,UIScrollView默认的contentInsetAdjustmentBehavior自动调整内边距和偏移的逻辑,也会加剧这种异常滚动的出现。
解决方法
方法一:锁定并恢复滚动偏移
在动画前后保存当前contentOffset,动画结束后强制恢复,避免系统自动调整:
@IBAction func add(_ sender: Any) { let customView = CustomView.instanceFromNib() // 保存当前滚动位置 let originalOffset = scrollView.contentOffset customView.hide() stackView.addArrangedSubview(customView) // 无动画执行布局更新,避免触发系统滚动 UIView.performWithoutAnimation { stackView.superview?.layoutIfNeeded() } customView.show() UIView.animate(withDuration: 1, animations: { self.stackView.superview?.layoutIfNeeded() }) { _ in // 动画完成后恢复原始滚动位置 self.scrollView.contentOffset = originalOffset } }
方法二:禁用自动调整行为
在viewDidLoad中关闭UIScrollView的自动内边距和偏移调整功能,从根源上阻止系统自动滚动:
override func viewDidLoad() { super.viewDidLoad() scrollView.contentInsetAdjustmentBehavior = .never }
注意:使用该方法后,需自行手动管理scrollView的内边距和内容布局,确保内容显示正常。
方法三:优化自定义视图约束逻辑
修改CustomView的隐藏/显示逻辑,通过修改约束constant值替代激活/禁用约束,让布局变化更平滑:
class CustomView: UIView { private var heightConstraint: NSLayoutConstraint! @IBOutlet weak var borderView: UIView! @IBOutlet weak var stackView: UIStackView! override func awakeFromNib() { super.awakeFromNib() borderView.layer.cornerRadius = stackView.frame.height / 2 borderView.layer.masksToBounds = true borderView.layer.borderWidth = 1 // 绑定高度约束,初始值为视图固有高度 heightConstraint = self.safeAreaLayoutGuide.heightAnchor.constraint(equalToConstant: stackView.frame.height) heightConstraint.isActive = true } func hide() { heightConstraint.constant = 0 } func show() { heightConstraint.constant = stackView.frame.height } }
对应的添加动画代码无需额外修改,保持原有逻辑即可。
推荐方案
优先尝试方法一,它无需改动原有约束结构,能快速解决问题;如果需要长期优化布局稳定性,可以结合方法二或方法三使用。
内容的提问来源于stack exchange,提问作者Cheok Yan Cheng
相关产品推荐
相关产品推荐

