直接上代码
extension UIView {
/// 实现一个点击扩散的水波纹动画
/// - Parameters:
/// - point: 点击点
/// - color: 波纹的颜色
/// - duration: 动画时长
public func runRippleAnimation(
point: CGPoint,
color: UIColor = .red,
duration: TimeInterval = 0.3
) {
let layerName = "ripperAnimation"
layer.sublayers?.forEach { layer in
if layer.name == layerName {
layer.removeFromSuperlayer()
}
}
let rippleLayer = CAShapeLayer()
rippleLayer.backgroundColor = UIColor.clear.cgColor
rippleLayer.path = UIBezierPath(ovalIn: CGRect(
x: point.x - 5,
y: point.y - 5,
width: 10,
height: 10
)).cgPath
rippleLayer.cornerRadius = bounds.height / 2
rippleLayer.fillColor = color.cgColor
layer.insertSublayer(rippleLayer, at: 0)
let maxXDistance = max(point.x, bounds.width - point.x)
let maxYDistance = max(point.y, bounds.height - point.y)
// 计算两点之间的最大距离
let maxDistance = sqrt(pow(maxXDistance, 2) + pow(maxYDistance, 2))
CATransaction.begin()
CATransaction.setCompletionBlock {
rippleLayer.removeFromSuperlayer()
}
// 路径动画
let animation = CABasicAnimation(keyPath: "path")
animation.fromValue = rippleLayer.path
animation.toValue = UIBezierPath(ovalIn: CGRect(
x: point.x - maxDistance,
y: point.y - maxDistance,
width: 2 * maxDistance,
height: 2 * maxDistance
)).cgPath
animation.timingFunction = CAMediaTimingFunction(name: .easeOut)
animation.fillMode = .forwards
// 透明度变化
let opacityAnimation = CABasicAnimation(keyPath: "opacity")
opacityAnimation.fromValue = 1
opacityAnimation.toValue = 0
let animationGroup = CAAnimationGroup()
animationGroup.duration = duration
animationGroup.timingFunction = CAMediaTimingFunction(name: .easeOut)
animationGroup.animations = [
animation,
opacityAnimation,
]
rippleLayer.add(animationGroup, forKey: "rippleAnimation")
// 动画开始
CATransaction.commit()
}
}