仿抖音點贊按鈕

FFIB發表於2018-07-17

每一個圖形,都是通過一點點拼接到一起的,而每一個動畫亦然,只需要將動畫和圖形進行拆解,就不難了。

模仿下抖音點贊按鈕的動畫效果。

仿抖音點贊按鈕
拆解一下動畫效果。

  • 紅色愛心逐漸變大的過程,並伴隨著有左右旋轉的效果。
  • 與此同時,伴隨著六個扇形塊向外擴散的效果。
  • 再次點選時,紅色愛心旋轉45°,逐漸變小。

具體實現

1、通過 UIBezierPath 實現愛心的上半部分。

let rect = CGRect(x: 10, y: 10, width: frame.width - 20, height: frame.height - 20)
//距離左右兩邊的距離
let padding: CGFloat = 4
let radius = (rect.size.width - 2 * padding) / 2.0 / (cos(CGFloat.pi / 4) + 1)
let heartPath = UIBezierPath()
//左圓的圓心
let leftCurveCenter = CGPoint(x: padding + radius, y: rect.size.height / 2.8)
//畫左圓
heartPath.addArc(withCenter: leftCurveCenter, radius: radius,
                 startAngle: CGFloat.pi, endAngle: CGFloat.pi * -0.25,
                 clockwise: true)
//右圓圓心
let rightCurveCenter = CGPoint(x: rect.width - padding - radius, y: leftCurveCenter.y)
//畫右圓
heartPath.addArc(withCenter: rightCurveCenter, radius: radius,
                 startAngle: CGFloat.pi * -0.75, endAngle: 0,
                 clockwise: true)

let shapeLayer = CAShapeLayer()
shapeLayer.path = heartPath.cgPath
shapeLayer.frame = rect
複製程式碼

仿抖音點贊按鈕
愛心的上半部分是由兩個 3/4 圓, 圓半徑的計算公式:(width - padding * 2) / 2 = radius + radius * cos45°,可得出 radius = (width - padding * 2) / 2 / (cos45° + 1),此公式是根據兩個半圓交點的切線呈 90°

2、通過 UIBezierPath 完成愛心的下半部分。其中愛心尖的位置,為整個 UIButton 的底部中心點

//愛心尖的座標點
let apexPoint = CGPoint(x: rect.width / 2, y: rect.height - padding)
//畫右半邊曲線
heartPath.addQuadCurve(to: apexPoint,
                       controlPoint: CGPoint(x: heartPath.currentPoint.x,
                                             y: radius + rect.size.height / 2.8))
//畫左半邊曲線
heartPath.addQuadCurve(to: CGPoint(x: padding, y: leftCurveCenter.y),
                       controlPoint: CGPoint(x: padding,
                                             y: radius + rect.size.height / 2.8))
複製程式碼

仿抖音點贊按鈕

3、此處採用兩個 layer 層,一個為白色的愛心,一個為紅色的愛心。通過白色愛心隱藏,紅色愛心逐漸變大,並伴隨左右旋轉。放大的動畫執行完,旋轉的動畫還未執行完,所以放大的動畫時間相對短一些

//放大動畫
let animation = CABasicAnimation.init(keyPath: "transform.scale")
animation.duration = 1 * 0.8
animation.fromValue = 0.1
animation.toValue = 1

//旋轉動畫
let keyAnimation = CAKeyframeAnimation.init(keyPath: "transform.rotation.z")
keyAnimation.values = [CGFloat.pi * -0.25, 0, CGFloat.pi * 0.1, CGFloat.pi * -0.05, 0]
keyAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut)
keyAnimation.duration = 1

//合成動畫組
let groupAnimation = CAAnimationGroup()
groupAnimation.duration = 1
groupAnimation.delegate = self
groupAnimation.animations = [keyAnimation, animation]
redHeartLayer.isHidden = false
hollowHeartLayer.isHidden = true
redHeartLayer.add(groupAnimation, forKey: nil)
複製程式碼

仿抖音點贊按鈕

4、顯示白色的愛心,紅色愛心向左旋轉45°,並且伴隨著縮小,其中旋轉動畫的時間比縮小動畫的時間短

//縮小動畫
let animation = CABasicAnimation(keyPath: "transform.scale")
animation.duration = 1
animation.fromValue = 1
animation.toValue = 0

//旋轉動畫
let keyAnimation = CAKeyframeAnimation.init(keyPath: "transform.rotation.z")
keyAnimation.values = [0, CGFloat.pi * -0.25]
keyAnimation.fillMode = .forwards
keyAnimation.duration = 1 * 0.4
let groupAnimation = CAAnimationGroup()

//合成動畫組
groupAnimation.duration = 1
groupAnimation.delegate = self
groupAnimation.animations = [keyAnimation, animation]
groupAnimation.fillMode = .forwards
groupAnimation.isRemovedOnCompletion = false
hollowHeartLayer.isHidden = false
redHeartLayer.add(groupAnimation, forKey: nil)
複製程式碼

仿抖音點贊按鈕

4、六條扇形

 let fanCenter = CGPoint(x: frame.width / 2, y: frame.height / 2)
 for i in 0..<6 {
     let path = UIBezierPath()
     
     //新增扇形圓弧。
     path.addArc(withCenter: fanCenter,
                 radius: frame.width / 2,
                 startAngle: CGFloat.pi / 2 + (CGFloat.pi / 3) * CGFloat(i) - (CGFloat.pi / 72),
                 endAngle: CGFloat.pi / 2 + CGFloat.pi / 3 * CGFloat(i) + CGFloat.pi / 72,
                 clockwise: true)
    
    //與中心點相連
     path.addLine(to: fanCenter)

     path.close()
     let fanLayer = CAShapeLayer()
     fanLayer.path = path.cgPath
     fanLayer.fillColor = UIColor.red.cgColor
     fanLayer.frame = bounds
     layer.addSublayer(fanLayer)
     animationLayers.append(fanLayer)
 }
複製程式碼

勾畫出六個扇形框,再設定 fillColor

仿抖音點贊按鈕
仿抖音點贊按鈕

5、扇形擴散動畫 通過中心點位置位移到扇形圓弧位置,以達到擴散的效果

let fanAnimation = CABasicAnimation(keyPath: "position")
fanAnimation.duration = animationDuration
fanAnimation.fromValue = CGPoint(x: frame.width / 2, y: frame.height / 2)
fanAnimation.toValue = path.currentPoint
fanAnimation.isRemovedOnCompletion = false
fanAnimation.delegate = self
fanAnimation.fillMode = .both
fanLayer.add(lineAnimation, forKey: nil)
複製程式碼

仿抖音點贊按鈕

6、看著效果有問題,需要給 UIButton加上蒙層,以達到扇形圖層逐漸消失的感覺,並且在動畫結束的時候將扇形圖層移除

//移除扇形圖層
 func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
     for animationLayer in animationLayers {
        animationLayer.removeFromSuperlayer()
        animationLayer.removeAllAnimations()
    }
    animationLayers.removeAll()
 }
 
 //新增蒙層
 fileprivate func configurationMaskLayer() {
    let maskPath = UIBezierPath(roundedRect: bounds,
                                cornerRadius: frame.width / 2)
    let maskLayer = CAShapeLayer()
    maskLayer.path = maskPath.cgPath
    layer.mask = maskLayer
}
複製程式碼

仿抖音點贊按鈕

7、將愛心動畫和扇形動畫合在一起

仿抖音點贊按鈕

下面附上 完整Demo

如果有更好的方法歡迎討論。

相關文章