直接上代碼
extension UIView {
/// 實(shí)現(xiàn)一個(gè)點(diǎn)擊擴(kuò)散的水波紋動(dòng)畫
/// - Parameters:
/// - point: 點(diǎn)擊點(diǎn)
/// - color: 波紋的顏色
/// - duration: 動(dòng)畫時(shí)長
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)
// 計(jì)算兩點(diǎn)之間的最大距離
let maxDistance = sqrt(pow(maxXDistance, 2) + pow(maxYDistance, 2))
CATransaction.begin()
CATransaction.setCompletionBlock {
rippleLayer.removeFromSuperlayer()
}
// 路徑動(dòng)畫
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")
// 動(dòng)畫開始
CATransaction.commit()
}
}