自定义Auto Layout视图点击按钮实现SlideLayout高度动画调整需求
嘿,这个需求在iOS布局动画里太常见啦,咱们一步步来实现,保证父视图和其他子视图都能跟着顺滑调整:
实现步骤详解
1. 先搞定基础约束:给SlideLayout加可修改的高度约束
首先核心要点是:不要把SlideLayout的高度写死,而是用一个属性存储它的高度约束,这样后续才能通过修改约束值实现展开/收起。
下面是CustomLayout的完整实现示例:
class CustomLayout: UIView { // 专门存SlideLayout的高度约束,方便后续修改 private var slideHeightConstraint: NSLayoutConstraint! override init(frame: CGRect) { super.init(frame: frame) setupSubviews() } required init?(coder: NSCoder) { super.init(coder: coder) setupSubviews() } private func setupSubviews() { backgroundColor = .blue // 1. 创建SlideLayout(红色自定义视图) let slideLayout = SlideLayout() slideLayout.backgroundColor = .red slideLayout.translatesAutoresizingMaskIntoConstraints = false addSubview(slideLayout) // 2. 创建黄色按钮 let toggleBtn = UIButton(type: .system) toggleBtn.backgroundColor = .yellow toggleBtn.setTitle("展开/收起", for: .normal) toggleBtn.addTarget(self, action: #selector(toggleSlideLayout), for: .touchUpInside) toggleBtn.translatesAutoresizingMaskIntoConstraints = false addSubview(toggleBtn) // 3. 创建浅灰色视图 let grayView = UIView() grayView.backgroundColor = .lightGray grayView.translatesAutoresizingMaskIntoConstraints = false addSubview(grayView) // 给SlideLayout设置初始高度约束(比如收起状态是60) slideHeightConstraint = slideLayout.heightAnchor.constraint(equalToConstant: 60) slideHeightConstraint.isActive = true // 垂直排列所有子视图的约束链 NSLayoutConstraint.activate([ // SlideLayout和父视图顶部、左右对齐 slideLayout.topAnchor.constraint(equalTo: topAnchor), slideLayout.leadingAnchor.constraint(equalTo: leadingAnchor), slideLayout.trailingAnchor.constraint(equalTo: trailingAnchor), // 按钮在SlideLayout下方,留16间距,左右留边,高度固定44 toggleBtn.topAnchor.constraint(equalTo: slideLayout.bottomAnchor, constant: 16), toggleBtn.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16), toggleBtn.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16), toggleBtn.heightAnchor.constraint(equalToConstant: 44), // 浅灰视图在按钮下方,和父视图底部对齐,左右撑满,高度固定100 grayView.topAnchor.constraint(equalTo: toggleBtn.bottomAnchor, constant: 16), grayView.leadingAnchor.constraint(equalTo: leadingAnchor), grayView.trailingAnchor.constraint(equalTo: trailingAnchor), grayView.bottomAnchor.constraint(equalTo: bottomAnchor), grayView.heightAnchor.constraint(equalToConstant: 100) ]) } // 按钮点击触发的切换逻辑 @objc private func toggleSlideLayout() { // 定义收起和展开的高度值,可根据需求调整 let collapsedHeight: CGFloat = 60 let expandedHeight: CGFloat = 200 // 切换高度约束的constant值 slideHeightConstraint.constant = slideHeightConstraint.constant == collapsedHeight ? expandedHeight : collapsedHeight // 执行动画,这里用0.3秒的缓动动画,效果更自然 UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseInOut) { // 必须在动画闭包里调用layoutIfNeeded,才能触发平滑的布局更新 self.layoutIfNeeded() } } } // 你的自定义SlideLayout类,这里简单示例 class SlideLayout: UIView { // 这里可以添加你的自定义UI内容 }
2. 确保父视图能自动跟着调整高度
要让CustomLayout本身也跟着动画改变高度,注意两个关键点:
- 不要给CustomLayout设置固定高度约束,让它的高度完全由内部子视图的约束链(top到bottom的连续约束)自动撑起。
- 如果CustomLayout是放在其他容器里(比如UIScrollView),要确保容器的约束允许它调整高度(比如ScrollView不需要固定contentSize,让子视图自动撑开)。
3. 动画细节优化(可选)
如果想让效果更丝滑:
- 可以调整动画的
duration时长,或者换成UIViewPropertyAnimator实现更复杂的动画曲线。 - 如果SlideLayout内部还有子视图,也可以在动画闭包里给它们添加属性动画(比如内部文本的位置变化),让整体过渡更协调。
关键避坑点
- 一定要在动画闭包里调用
layoutIfNeeded(),而不是setNeedsLayout()——后者只会标记布局需要更新,不会立即执行,动画就不会生效。 - 所有子视图必须设置
translatesAutoresizingMaskIntoConstraints = false,否则Auto Layout约束会失效。
内容的提问来源于stack exchange,提问作者Dex
相关产品推荐
相关产品推荐

