求助:使用SnapKit实现视图动画无效果问题排查
解决SnapKit约束动画不生效的问题
我仔细看了你的代码,动画直接显示没有过渡效果,主要是几个关键环节没处理对,咱们一步步来修正:
1. 初始约束未设置正确的起始状态
你在setupMatchView最后调用hideMatch()来隐藏视图,但hideMatch()里是通过snp.updateConstraints修改位置,这时候初始约束已经是centerY.equalToSuperview()了,布局系统没法正确记录"从哪里动画到哪里"的状态。
正确的做法是在初始化matchView时,就把它的初始位置设置到屏幕外,而不是依赖后续的约束更新:
// 在setupMatchView的matchView约束设置中,修改centerY的初始值 matchView.snp.makeConstraints { (make) in make.left.equalToSuperview().offset(32) make.right.equalToSuperview().inset(32) make.centerX.equalToSuperview() // 初始就把视图放在屏幕下方不可见区域 make.centerY.equalToSuperview().offset(self.view.frame.height) }
同时把matchOverlayView的初始透明度设为0,不需要再调用hideMatch()初始化状态。
2. 动画时要触发父视图的布局更新
你当前在动画块里调用self.matchView.layoutIfNeeded(),但matchView的约束是相对于父视图(self.view)的,必须让父视图触发布局更新,约束变化才能正确驱动动画:
UIView.animate(withDuration: 2) { self.view.layoutIfNeeded() }
3. 透明度变化要放到动画块内
你现在直接设置matchOverlayView.alpha,会导致透明度瞬间变化,没有过渡效果,需要把这个操作移到动画闭包中。
修改后的完整代码片段
private func setupMatchView() { view.addSubview(matchOverlayView) matchOverlayView.snp.makeConstraints { (make) in make.top.equalTo(view.safeAreaLayoutGuide.snp.topMargin) make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottomMargin) make.left.equalToSuperview() make.right.equalToSuperview() } matchOverlayView.backgroundColor = UIColor.white.withAlphaComponent(0.5) // 初始透明度设为0 matchOverlayView.alpha = 0 view.addSubview(matchView) matchView.snp.makeConstraints { (make) in make.left.equalToSuperview().offset(32) make.right.equalToSuperview().inset(32) make.centerX.equalToSuperview() // 初始位置放在屏幕下方 make.centerY.equalToSuperview().offset(self.view.frame.height) } matchView.backgroundColor = .white matchView.layer.cornerRadius = 8 matchView.dropShadow() // --- 以下子视图约束代码保持不变 --- matchView.addSubview(matchYourImageView) matchYourImageView.snp.makeConstraints { (make) in make.height.width.equalTo(100) make.centerX.equalToSuperview().inset(20) make.top.equalToSuperview().offset(40) } matchYourImageView.backgroundColor = UIColor(red:0.77, green:0.77, blue:0.77, alpha:1.00) matchYourImageView.layer.cornerRadius = 50 matchYourImageView.clipsToBounds = true matchView.addSubview(matchHerImageView) matchHerImageView.snp.makeConstraints { (make) in make.height.width.equalTo(100) make.centerX.equalToSuperview().inset(-20) make.top.equalTo(matchYourImageView.snp.top) } matchHerImageView.backgroundColor = UIColor(red:0.69, green:0.69, blue:0.69, alpha:1.00) matchHerImageView.layer.cornerRadius = 50 matchHerImageView.clipsToBounds = true matchView.addSubview(matchLabel) matchLabel.snp.makeConstraints { (make) in make.top.equalTo(matchYourImageView.snp.bottom).offset(64) make.centerX.equalToSuperview() } matchLabel.text = "Match" matchLabel.font = UIFont.systemFont(ofSize: 28, weight: .heavy) matchView.addSubview(matchCTA) matchCTA.snp.makeConstraints { (make) in make.top.equalTo(matchLabel.snp.bottom).offset(40) make.left.equalToSuperview().offset(32) make.right.equalToSuperview().inset(32) make.height.equalTo(44) make.bottom.equalToSuperview().inset(40) } matchCTA.setTitle("Go To Chat", for: .normal) matchView.addSubview(matchCloseButton) matchCloseButton.snp.makeConstraints { (make) in make.width.equalTo(32) make.height.equalTo(32) make.right.equalToSuperview().inset(16) make.top.equalToSuperview().inset(16) } matchCloseButton.setImage(UIImage(named: "Close"), for: .normal) matchCloseButton.addTarget(self, action: #selector(self.closeButtonTapped(_:)), for:.touchUpInside) // 确保初始布局生效 view.layoutIfNeeded() } @objc func closeButtonTapped(_ sender:UIButton) { hideMatch() } private func hideMatch() { matchView.snp.updateConstraints { (make) in make.centerY.equalToSuperview().offset(self.view.frame.height) } UIView.animate(withDuration: 1) { self.matchOverlayView.alpha = 0 self.view.layoutIfNeeded() } } private func showMatch() { matchView.snp.updateConstraints { (make) in make.centerY.equalToSuperview().offset(0) } UIView.animate(withDuration: 2) { self.matchOverlayView.alpha = 1 self.view.layoutIfNeeded() } }
额外小提示
如果想让动画更有弹性,可以试试弹簧动画API:
UIView.animate(withDuration: 0.8, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.5, options: [], animations: { self.matchOverlayView.alpha = 1 self.view.layoutIfNeeded() }, completion: nil)
内容的提问来源于stack exchange,提问作者Kira
相关产品推荐
相关产品推荐

