如何在垂直UIStackView中正确实现子项高度变更的流畅动画
UIStackView 子视图高度动画同步问题修复方案
问题场景
有一个红色的UIStackView,内部包含一个标签和一个紫色自定义视图,初始效果如下:
需求
- 动画过程中标签的左上角(x,y)坐标始终保持不变
- 动画过程中紫色自定义视图的左上角(x,y)坐标始终保持不变
- 动画过程中红色UIStackView可跟随紫色自定义视图的高度变化实现平滑过渡动画
现有实现代码
class ViewController: UIViewController { @IBOutlet weak var purpleView: UIView! @IBOutlet weak var stackView: UIStackView! @IBOutlet weak var purpleViewHeightConstraint: NSLayoutConstraint! override func viewDidLoad() { super.viewDidLoad() } var value: CGFloat = 200.0 @IBAction func buttonClicked(_ sender: Any) { value = value == 500 ? 200.0 : 500.0 UIView.animate(withDuration: 2) { self.purpleViewHeightConstraint.constant = self.value self.purpleView.setNeedsLayout() self.purpleView.layoutIfNeeded() } } }
存在问题
当前实现效果如下:
红色UIStackView的高度会突然变化,无法跟随其子视图紫色view的动画同步过渡,要求不删除UIStackView的前提下实现上述需求。
修复方案
问题根源是动画块内只触发了紫色视图本身的布局刷新,没有触发上层StackView所在的视图层级的布局计算,修改动画块代码如下即可:
UIView.animate(withDuration: 2) { self.purpleViewHeightConstraint.constant = self.value // 调用根视图的layoutIfNeeded触发整棵视图树的布局刷新 self.view.layoutIfNeeded() }
原理说明
约束变更的动画需要对应视图的父层级参与布局计算才能生效,调用根视图的layoutIfNeeded()会从顶层开始往下同步计算所有子视图的尺寸:
- 紫色视图的高度会跟着约束的渐变过程平滑更新
- StackView会同步响应子视图的尺寸变化,自身高度跟着渐变
- 标签和紫色视图的左上角坐标因为StackView的顶部对齐排布规则,全程不会发生位移,完全符合需求。
内容的提问来源于stack exchange,提问作者Cheok Yan Cheng
相关产品推荐
相关产品推荐

