UIKit:如何对代码创建的约束变更做动画,实现顶部通知滑入效果
问题1:动画异常的原因与修复
你遇到的动画反向问题是两个错误共同导致的:
- 横向约束写错了,你原本的代码里第二个约束是
customTopView.constraint(equalTo: customTopView.trailingAnchor, constant: 20.0),相当于让视图自己的锚点和自己做约束,完全无法确定横向宽度,后续的高度计算和布局都会出错。正确的横向约束应该是父视图的右锚点等于弹窗视图的右锚点加20。 - 约束逻辑写反,且重复添加约束导致冲突。你初始设置的是
customTopView.topAnchor等于父视图topAnchor的偏移为负的高度(也就是藏在屏幕顶部外),动画时新建了反向约束self.topAnchor.constraint(equalTo: customTopView.topAnchor, constant: 100.0),换算后等于要求弹窗的top在父视图top上方100pt,自然会向上消失。正确做法是保存初始的top约束,动画时直接修改它的constant值即可。
修正后的动画逻辑代码如下:
extension UIView { func showCustomTopView(withTitle title: NSAttributedString, subtitle: NSAttributedString) { let customTopView = CustomTopView.instance(withTitle: title, subtitle: subtitle) addSubview(customTopView) customTopView.translatesAutoresizingMaskIntoConstraints = false // 修正横向约束 NSLayoutConstraint.activate([ customTopView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20.0), trailingAnchor.constraint(equalTo: customTopView.trailingAnchor, constant: 20.0), ]) // 先触发一次布局拿到正确的自适应高度 layoutIfNeeded() // 保存top约束变量 let topConstraint = customTopView.topAnchor.constraint(equalTo: topAnchor, constant: -customTopView.bounds.height) topConstraint.isActive = true // 先触发初始布局,让视图停留在屏幕外 layoutIfNeeded() // 执行动画 UIView.animate(withDuration: 0.5) { // 直接修改约束的偏移值,让弹窗顶部到父视图顶部100pt的位置 topConstraint.constant = 100 // 父视图触发布局更新 self.layoutIfNeeded() } } }
问题2:// *处代码的正确性
你的思路是对的,这行代码的作用就是让系统完成布局计算,拿到自适应内容后的视图高度。不过有两个优化点:
- 应该调用父视图的
layoutIfNeeded()而不是弹窗自己的,因为弹窗的布局依赖父视图的约束设置,父视图触发布局才能得到准确的尺寸。 - 你也可以主动计算自适应大小,不需要依赖布局刷新:
let targetSize = customTopView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) let viewHeight = targetSize.height
这种方式不需要调用layoutIfNeeded也能拿到准确的自适应高度,适配性更好。
内容的提问来源于stack exchange,提问作者Dannis Case
相关产品推荐
相关产品推荐

