iOS实现抖音点赞动画效果

时间:2021-09-01 13:54:34

本文实例为大家分享了iOS实现抖音点赞动画的具体代码,供大家参考,具体内容如下

1. 概述

 

最近看到抖音点赞爱心的动画效果比较好,出于好奇,自己也研究仿照动画效果写了一个,不喜欢的朋友可不要喷我噢!!!

话不多说,先来看一下执行效果。

iOS实现抖音点赞动画效果

2. 动画分析

 

上面的示例效果有点快,现在来看一个慢的,然后在分析动画组成。

iOS实现抖音点赞动画效果

这回看清楚了吧,哈哈。

2.1 动画过程分析

咱们就以10秒的点赞动画来分析一下:

点赞的时候:

1、点击的时候,白色爱心逐渐变小到一定程度,然后变成红色爱心。(3秒)
2、红色爱心慢慢变大,最终有个缓冲动画,然后恢复原尺寸。(7秒)
3、在红色爱心变大的时候,有一个红色的圆环逐渐变大,圆环宽度由小变大,再变小消失。(5秒)
4、在红色爱心变大的时候,还有6个环绕爱心的三角形,三角形由小变大,再变小消失。(7秒)
5、注意,2、3、4的动画是在1动画结束后同时执行的,即延迟3秒再执行。

取消点赞的时候:

1、点击后红色爱心逐渐变小。
2、变小后,设置不可见,并恢复原尺寸。

2.2 代码实现原理分析

1、自定义一个UIView,并添加两个UIImageView,分别显示红色爱心和白色爱心,红色爱心在白色爱心上面,并设置红色爱心不可见。
2、给UIView添加单击手势。
3、点击时判断是点赞还是取消点赞,如果是点赞:
4、用两个UIView自带的动画,将白色ImageView的transform变小,变小后不可见,然后设置红色ImageView的transform变大,变大后白色ImageView的transform变回原尺寸。
5、通过贝塞尔曲线和CAShapeLayer绘制圆环,并给圆环添加动画组CAAnimationGroup,动画组中添加了一个基础动画CABasicAnimation(将圆环从小变大)和一个关键帧动画CAKeyframeAnimation(将圆环宽度由小变大再变小消失)
6、通过贝塞尔曲线和CAShapeLayer循环绘制6个三角形,并通过CATransform3DMakeRotation旋转6个三角形,使其环绕爱心一周。
7、给每个三角形添加一个关键帧动画CAKeyframeAnimation(将三角形由小变大再变小消失)
8、如果是取消点赞,比较简单,逐渐将红色爱心变小,然后设置不可见,白色爱心自然就显示出来了。
9、在动画执行过程中,关闭用户交互,待动画结束,再打开用户交互。

分析的有些简单,只是提供一种思路,没有什么比看代码更直接的了,来吧!

3. 全部代码

 

代码中添加了很多的注释,方便理解。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
import UIKit
 
public class LikeView: UIView {
 
 // 红色爱心视图
 fileprivate var likeImageView = UIImageView()
 // 白色爱心视图
 fileprivate var unLikeImageView = UIImageView()
 // true: 点赞, false:取消点赞
 fileprivate var isLike: Bool = false
 // 动画时长,可设置
 public var duration: CFTimeInterval = 0.5
 
 override init(frame: CGRect) {
 super.init(frame: frame)
 setupUI()
 }
 
 required init?(coder: NSCoder) {
 super.init(coder: coder)
 setupUI()
 }
 
 fileprivate func setupUI() {
 // 添加白色爱心视图
 unLikeImageView.frame = CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height)
 unLikeImageView.image = UIImage(named: "icon_like_before")
 addSubview(unLikeImageView)
 
 // 添加红色爱心视图,并设置不可看。切记红色爱心在在白色爱心的上面。
 likeImageView.frame = CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height)
 likeImageView.image = UIImage(named: "icon_like_after")
 likeImageView.alpha = 0
 addSubview(likeImageView)
 
 // 添加单击手势
 let tap = UITapGestureRecognizer(target: self, action: #selector(tapLikeAction))
 self.addGestureRecognizer(tap)
 }
 
 // 点击事件
 @objc fileprivate func tapLikeAction() {
 // 点击的时候停止交互,以免反复点击。
 self.isUserInteractionEnabled = false
 isLike = !isLike
 
 // 点赞
 if isLike {
 // 设置红色爱心不可见
 likeImageView.alpha = 0
 
 // 将红色爱心缩小至原来0.2倍。
 self.likeImageView.transform = CGAffineTransform(scaleX: 0.2, y: 0.2)
 
 /* 添加动画, 使白色爱心变小,红色爱心变大,此过程占用全部动画时长。*/
 
 UIView.animate(withDuration: duration * 0.3, delay: 0, options: .curveEaseInOut) { [weak self] in
 // 将白色爱心逐渐变小至0.2倍,
 self?.unLikeImageView.transform = CGAffineTransform(scaleX: 0.2, y: 0.2)
 } completion: { [weak self] (finished) in
 // 设置红色爱心可见,此时是0.2倍大小。
 self?.likeImageView.alpha = 1
 let duration = self?.duration ?? 0.5
 // 白色爱心变小后,继续操作红色爱心
 UIView.animate(withDuration: duration * 0.7, delay: 0.1, usingSpringWithDamping: 0.6, initialSpringVelocity: 0.8, options: .curveEaseInOut) {
  // 将红色爱心恢复原大小
  self?.likeImageView.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
 } completion: { (finished) in
  // 红色爱心变大后,恢复白色爱心的尺寸,开启用户交互。
  self?.unLikeImageView.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
  self?.isUserInteractionEnabled = true
 }
 }
 
 //***************** 以下是圆环动画,在红色爱心变大的时候执行。******************//
 
 // 小圆环路径
 let circleStartPath = UIBezierPath(arcCenter: likeImageView.layer.position, radius: self.bounds.size.width / 6, startAngle: 0, endAngle: CGFloat(2*Double.pi), clockwise: true)
 
 // 大圆环路径
 let radius = sqrt(powf(Float(self.bounds.size.width), 2) + powf(Float(self.bounds.size.height), 2))/2
 let circleEndPath = UIBezierPath(arcCenter: likeImageView.layer.position, radius: CGFloat(radius), startAngle: 0, endAngle: CGFloat(2*Double.pi), clockwise: true)
 
 // 创建圆环图层,用于显示圆环。
 let circleLayer = CAShapeLayer()
 circleLayer.strokeColor = UIColor.red.cgColor
 circleLayer.fillColor = UIColor.clear.cgColor
 self.layer.insertSublayer(circleLayer, below: self.likeImageView.layer)
 
 // 计算圆环图层的偏移时间
 var currentTimeInSuper = self.layer.convertTime(CACurrentMediaTime(), from: nil)
 var currentTimeLocal = circleLayer.convertTime(currentTimeInSuper, from: self.layer)
 
 // 设置圆环动画组执行时间
 let circleGroupDuration = duration * 0.5
 
 // 圆环动画组
 let circleGroup = CAAnimationGroup()
 circleGroup.duration = circleGroupDuration
 // 圆环动画组开始时间,此开始时间正好是白色爱心变小后,红色爱心开始变大时。
 circleGroup.beginTime = currentTimeLocal + duration * 0.3
 
 // 设置圆环路径变化动画
 let circlePathAnimation = CABasicAnimation(keyPath: "path")
 circlePathAnimation.fromValue = circleStartPath.cgPath
 circlePathAnimation.toValue = circleEndPath.cgPath
 
 // 设置圆环宽度变化动画,先变大,再变小。
 let circleLineWidthAnimation = CAKeyframeAnimation(keyPath: "lineWidth")
 circleLineWidthAnimation.values = [1.0, 4.0, 0.3]
 circleLineWidthAnimation.keyTimes = [0.0, 0.7, 0.9]
 
 // 将圆环的两个动画添加到动画组。
 circleGroup.animations = [circlePathAnimation, circleLineWidthAnimation]
 
 // 将动画添加到圆环图层。
 circleLayer.add(circleGroup, forKey: nil)
 //**********************************************************************//
 
 //***************** 以下是周围6个三角形放射动画,在红色爱心变大的时候执行。******************//
 // 循环创建三角形图层,并添加动画效果
 for i in 0..<6 {
 // 三角形的高
 let height = self.bounds.size.height / 2 + 12
 // 三角形底边长
 let width = self.bounds.size.width / 10
 
 // 绘制一个起始三角形路径
 let triangleStartPath = UIBezierPath()
 triangleStartPath.move(to: .zero)
 triangleStartPath.addLine(to: CGPoint(x: -1, y: -1))
 triangleStartPath.addLine(to: CGPoint(x: 1, y: -1))
 triangleStartPath.close()
 
 // 绘制一个完全展开的三角形路径
 let triangleMiddlePath = UIBezierPath()
 triangleMiddlePath.move(to: .zero)
 triangleMiddlePath.addLine(to: CGPoint(x: -width/2, y: -height))
 triangleMiddlePath.addLine(to: CGPoint(x: width/2, y: -height))
 triangleMiddlePath.close()
 
 // 绘制一个终了三角形路径
 let triangleEndPath = UIBezierPath()
 triangleEndPath.move(to: CGPoint(x: 0, y: -height))
 triangleEndPath.addLine(to: CGPoint(x: -width/2, y: -height))
 triangleEndPath.addLine(to: CGPoint(x: width/2, y: -height))
 triangleEndPath.close()
 
 // 绘制三角形图层
 let shapeLayer = CAShapeLayer()
 // 设置图层中心位置,很重要。
 shapeLayer.position = self.likeImageView.layer.position
 shapeLayer.fillColor = UIColor.red.cgColor
 // 将图层进行旋转。
 shapeLayer.transform = CATransform3DMakeRotation(CGFloat(Double.pi/3) * CGFloat(i), 0, 0, 1)
 
 self.layer.insertSublayer(shapeLayer, below: circleLayer)
 
 // 计算三角形图层的偏移时间
 currentTimeInSuper = self.layer.convertTime(CACurrentMediaTime(), from: nil)
 currentTimeLocal = shapeLayer.convertTime(currentTimeInSuper, from: self.layer)
 
 // 设置三角形的动画,由小变大再变小。
 let trianglePathAnimation = CAKeyframeAnimation(keyPath: "path")
 trianglePathAnimation.values = [triangleStartPath.cgPath, triangleMiddlePath.cgPath, triangleEndPath.cgPath]
 trianglePathAnimation.keyTimes = [0.0, 0.3, 0.7]
 trianglePathAnimation.duration = duration * 0.7
 trianglePathAnimation.beginTime = currentTimeLocal + duration * 0.3
 
 shapeLayer.add(trianglePathAnimation, forKey: nil)
 }
 //**********************************************************************//
 }else {
 // 取消点赞
 // 1. 将红色爱心逐渐缩小至原来的0.1倍,然后设置为不可见并恢复原尺寸大小。
 UIView.animate(withDuration: duration * 0.3, delay: 0, options: .curveEaseInOut) { [weak self] in
 self?.likeImageView.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
 } completion: { [weak self] (finished) in
 self?.likeImageView.alpha = 0
 self?.likeImageView.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
 self?.isUserInteractionEnabled = true
 }
 }
 }
}

LikeView即是自定义的点赞视图,可纯代码创建,也可通过xib创建,同时支持设置动画执行时间duration。

调用的地方:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class ViewController: UIViewController {
 
 override func viewDidLoad() {
 super.viewDidLoad()
 view.backgroundColor = UIColor.black
 // 设置一个0.5秒的动画
 let likeView1 = LikeView(frame: CGRect(x: 110, y: 300, width: 50, height: 50))
 likeView1.duration = 0.5
 self.view.addSubview(likeView1)
 
 // 设置一个10秒的动画
 let likeView2 = LikeView(frame: CGRect(x: 240, y: 300, width: 50, height: 50))
 likeView2.duration = 10
 self.view.addSubview(likeView2)
 }
 
}

执行效果:

iOS实现抖音点赞动画效果

4. 结束语

 

代码中主要用到了:UIView基础动画、CGAffineTransform、CATransform3D、UIBezierPath、CAShapeLayer、CAKeyframeAnimation、CABasicAnimation、CAAnimationGroup,另外还有beginTime的计算,也算是个小重点了。

以上只是仿照抖音点赞动画实现的功能,代码不多,但也不少,不知道抖音是具体怎么实现的,如果有什么不对的地方,或者可优化的地方,还请路过的朋友多多指点。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/guoyongming925/article/details/113258425