每一个图形,都是通过一点点拼接到一起的,而每一个动画亦然,只需要将动画和图形进行拆解,就不难了。
模仿下抖音点赞按钮的动画效果。
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 = Path
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
Value = 1//旋转动画
let keyAnimation = CAKeyframeAnimation.init(keyPath: ation.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
Value = 0//旋转动画
let keyAnimation = CAKeyframeAnimation.init(keyPath: ation.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 = PathfanLayer.fillColor = ColorfanLayer.frame = boundslayer.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)
Value = 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 {veFromSuperlayer()veAllAnimations()}veAll()}//添加蒙层fileprivate func configurationMaskLayer() {let maskPath = UIBezierPath(roundedRect: bounds,cornerRadius: frame.width / 2)let maskLayer = CAShapeLayer()maskLayer.path = Pathlayer.mask = maskLayer
}
复制代码
7、将爱心动画和扇形动画合在一起
下面附上 完整Demo
如果有更好的方法欢迎讨论。
本文发布于:2024-01-31 04:17:36,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170664585625393.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |