You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现视频中点击触发光泽摆动效果的阴影动画按钮?

优化带阴影的动画按钮:点击同时触发光泽+摆动,避免偏移

我来帮你把按钮的动画逻辑整合优化,确保一次点击就能同步触发光泽扫过和摆动效果,而且动画结束后按钮稳稳回到原位,不会跑偏~

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:34:42