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

点击View后的动画:如何在Swift中实现此类涟漪效果?

Hey there! 很高兴帮你解决Swift里点击View的涟漪效果实现问题,我给你整理了几种实用的方案,从最简单的原生实现到自定义动画都有,你可以根据需求选~

方法1:直接用UIButton的原生涟漪效果

如果你的View可以替换成UIButton,那这绝对是最省心的方案——UIButton在iOS 10+自带了触摸涟漪效果,完全不用自己写动画逻辑,几行代码就能搞定:

let rippleButton = UIButton(type: .system)
rippleButton.frame = CGRect(x: 50, y: 50, width: 200, height: 50)
rippleButton.setTitle("点击我", for: .normal)
// 自定义涟漪颜色(可选,默认用系统tint色)
rippleButton.tintColor = .systemBlue
rippleButton.backgroundColor = .systemGray5
view.addSubview(rippleButton)

点击这个Button时,会自动从触摸点扩散出半透明的涟漪,你还能通过tintColor调整涟漪的颜色,完美适配大部分场景。

方法2:给普通UIView自定义涟漪动画

如果必须用UIView(比如一些自定义的容器View),我们可以通过CAShapeLayer配合核心动画来实现点击扩散的效果。我平时做项目的时候会把这个逻辑封装成UIView的扩展,方便复用:

extension UIView {
    func addRippleEffect(at touchPoint: CGPoint) {
        // 1. 创建初始大小为0的圆形Layer
        let rippleLayer = CAShapeLayer()
        let startPath = UIBezierPath(ovalIn: CGRect(origin: touchPoint, size: .zero))
        rippleLayer.path = startPath.cgPath
        rippleLayer.fillColor = UIColor.systemBlue.withAlphaComponent(0.3).cgColor
        self.layer.addSublayer(rippleLayer)
        
        // 2. 计算最终的圆形大小(要覆盖整个View)
        let maxSide = max(self.bounds.width, self.bounds.height)
        let endFrame = CGRect(
            x: touchPoint.x - maxSide/2,
            y: touchPoint.y - maxSide/2,
            width: maxSide,
            height: maxSide
        )
        let endPath = UIBezierPath(ovalIn: endFrame).cgPath
        
        // 3. 组合扩散动画+透明度消失动画
        let pathAnim = CABasicAnimation(keyPath: "path")
        pathAnim.fromValue = startPath.cgPath
        pathAnim.toValue = endPath
        pathAnim.duration = 0.6
        
        let opacityAnim = CABasicAnimation(keyPath: "opacity")
        opacityAnim.fromValue = 0.3
        opacityAnim.toValue = 0
        opacityAnim.duration = 0.6
        
        let groupAnim = CAAnimationGroup()
        groupAnim.animations = [pathAnim, opacityAnim]
        groupAnim.timingFunction = CAMediaTimingFunction(name: .easeOut)
        groupAnim.fillMode = .forwards
        groupAnim.isRemovedOnCompletion = false
        
        rippleLayer.add(groupAnim, forKey: "rippleEffect")
        
        // 4. 动画结束后移除Layer,避免内存泄漏
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.6) {
            rippleLayer.removeFromSuperlayer()
        }
    }
}

然后给你的UIView添加点击手势,调用这个方法就行:

let customView = UIView(frame: CGRect(x: 50, y: 150, width: 200, height: 50))
customView.backgroundColor = .systemGray5
customView.isUserInteractionEnabled = true
view.addSubview(customView)

// 添加点击手势
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleViewTap(_:)))
customView.addGestureRecognizer(tapGesture)

// 处理点击事件
@objc private func handleViewTap(_ gesture: UITapGestureRecognizer) {
    guard let tappedView = gesture.view else { return }
    let touchPoint = gesture.location(in: tappedView)
    tappedView.addRippleEffect(at: touchPoint)
}

这个方案的好处是完全自定义,你可以调整动画时长、涟漪颜色、缓动效果,适配任何UIView。

方法3:SwiftUI中的涟漪效果实现

如果是用SwiftUI开发,那就更简单了,不管是用Button还是普通View都能轻松实现:

系统原生方案(Button)

SwiftUI的Button默认就带涟漪效果,只需要简单设置:

struct RippleDemoView: View {
    var body: some View {
        Button(action: {
            // 点击后的逻辑
        }) {
            Text("点击我")
                .frame(width: 200, height: 50)
                .background(Color.systemGray5)
        }
        .tint(.systemBlue) // 调整涟漪颜色
        .buttonStyle(.plain) // 或者用.automatic,默认就有涟漪
    }
}

自定义普通View的涟漪效果

如果要给非Button的View加涟漪,用TapGesture配合状态动画就行:

struct CustomRippleSwiftUIView: View {
    @State private var ripplePos: CGPoint = .zero
    @State private var rippleScale: CGFloat = 0
    @State private var rippleOpacity: Double = 0.3
    
    var body: some View {
        ZStack {
            Color.systemGray5
                .frame(width: 200, height: 50)
                .onTapGesture { location in
                    // 重置涟漪状态
                    ripplePos = location
                    rippleScale = 0
                    rippleOpacity = 0.3
                    
                    // 执行扩散+消失动画
                    withAnimation(.easeOut(duration: 0.6)) {
                        rippleScale = max(200, 50) * 2 // 确保覆盖整个View
                        rippleOpacity = 0
                    }
                }
            
            // 涟漪视图
            Circle()
                .fill(Color.systemBlue.opacity(rippleOpacity))
                .frame(width: rippleScale, height: rippleScale)
                .position(ripplePos)
        }
    }
}

小提示

  • 自定义动画时,记得在动画结束后清理资源(比如UIKit里移除Layer),避免内存泄漏
  • 可以调整duration和timingFunction来改变涟漪的快慢和弹性效果
  • 涟漪颜色建议用主色调的半透明色,这样既不突兀又能和App风格统一

内容的提问来源于stack exchange,提问作者Harshal Pathak

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 12:21:29