如何实现视频中点击触发光泽摆动效果的阴影动画按钮?
优化带阴影的动画按钮:点击同时触发光泽+摆动,避免偏移
我来帮你把按钮的动画逻辑整合优化,确保一次点击就能同步触发光泽扫过和摆动效果,而且动画结束后按钮稳稳回到原位,不会跑偏~
1. 优化自定义按钮类 ButtonWithShadow
咱们把所有动画逻辑封装在这个自定义类里,让ViewController只负责基础配置即可:
import UIKit class ButtonWithShadow: UIButton { // 用于实现扫光效果的光泽层 private let shineLayer = CAGradientLayer() override init(frame: CGRect) { super.init(frame: frame) setupButton() } required init?(coder: NSCoder) { super.init(coder: coder) setupButton() } private func setupButton() { // 初始化阴影配置 layer.shadowColor = UIColor.black.cgColor layer.shadowOpacity = 0.3 layer.shadowOffset = CGSize(width: 0, height: 2) layer.shadowRadius = 4 layer.masksToBounds = false // 保证阴影不被圆角裁剪 // 初始化光泽层(默认隐藏在按钮左侧外) shineLayer.colors = [UIColor.white.withAlphaComponent(0).cgColor, UIColor.white.withAlphaComponent(0.6).cgColor, UIColor.white.withAlphaComponent(0).cgColor] shineLayer.startPoint = CGPoint(x: -0.5, y: 0.5) shineLayer.endPoint = CGPoint(x: 1.5, y: 0.5) shineLayer.frame = bounds layer.addSublayer(shineLayer) shineLayer.opacity = 0 } // 重写点击事件,触发组合动画 override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesBegan(touches, with: event) triggerCombinedAnimation() } // 核心:同步执行摆动+光泽动画 private func triggerCombinedAnimation() { // 先重置按钮状态,避免之前的动画残留偏移 transform = .identity // 用关键帧动画把两个效果绑定在一起,保证同步触发 UIView.animateKeyframes(withDuration: 0.6, delay: 0, options: .calculationModeCubic) { // 第一部分:小幅度摆动动画(左右晃动后回到原位) UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.4) { self.transform = CGAffineTransform(rotationAngle: CGFloat.pi / 20) } UIView.addKeyframe(withRelativeStartTime: 0.2, relativeDuration: 0.4) { self.transform = CGAffineTransform(rotationAngle: -CGFloat.pi / 20) } UIView.addKeyframe(withRelativeStartTime: 0.4, relativeDuration: 0.2) { self.transform = .identity // 强制回到初始位置 } // 第二部分:光泽扫过动画 UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.6) { self.shineLayer.opacity = 1 self.shineLayer.transform = CATransform3DMakeTranslation(self.bounds.width, 0, 0) } } completion: { _ in // 动画结束后重置光泽层,为下一次点击做准备 self.shineLayer.opacity = 0 self.shineLayer.transform = .identity } } }
2. ViewController 简化调用
现在ViewController里只需要正常关联按钮,做基础样式配置就行:
import UIKit class ViewController: UIViewController { @IBOutlet weak var aBtn: ButtonWithShadow! override func viewDidLoad() { super.viewDidLoad() // 可以在这里添加按钮的基础样式 aBtn.setTitle("点我试试", for: .normal) aBtn.backgroundColor = UIColor.systemBlue aBtn.layer.cornerRadius = 8 aBtn.setTitleColor(.white, for: .normal) } }
关键优化点说明
- 同步动画触发:用
UIView.animateKeyframes将摆动和光泽动画放在同一个动画块中,确保点击时两个效果同时启动,不会有先后延迟。 - 彻底避免偏移:每次动画开始前先把
transform重置为.identity,摆动动画的最后一帧也强制回到原位,彻底杜绝按钮跑偏的问题。 - 性能优化:光泽层作为按钮的常驻子层,动画结束后重置状态而非重新创建,提升动画流畅度。
- 阴影稳定性:保持
masksToBounds = false,让阴影不会被按钮圆角裁剪,效果更自然。
这样调整后,点击按钮就能同时看到光泽扫过和小幅度摆动的效果,动画结束后按钮会稳稳回到初始位置~
内容的提问来源于stack exchange,提问作者Haitham Abdel Wahab
相关产品推荐
相关产品推荐

