絮叨一波
最近做一个基于地图sdk的项目,里面需要用到类似滴滴打车的大头针跳动动画,作为一名合格的程序员,遇到需求怎么可能不上来就Baidu一波轮子呢?然而,搜了半天并没有搜到轮子,我也很奇怪,到底是关键词不对,还是太简单了确实没有现成的轮子。不管了,最后决定自己实现一波。成品在这 -> SRPinView
分析
刚开始打开滴滴打车首页分析动画,由于动画太快(总共也才0.4s),看得一头雾水,后来经过一波慢放分析,发现动画一共分为4个阶段,5个状态。

整个视图的结构可以简单看成头部圆圈,和脚部的小尾巴,实际上,还有脚底部模拟的小影子(SRPinView中我做动画时候并没有带着小影子一起跳,我觉得这样更合理一些),动画一共有5个状态,经历4次动画。
- 常态,可以看成大头针平时是半蹲着的
- 准备起跳,就像从半蹲站起来,脚部被拉长,连带着头一起往上拉高
- 跳起来,脚步离开地面,头也往地下降,两者相互靠拢
- 头和脚缩短到最小距离,然后一起落下模拟自由落体
- 落下,这时候是全蹲着的状态(就像人落地时候蹲下身子缓冲动力一样),然后拉长脚并升高头到原始状态。
上代码
let hFrame = pinHeadView.frame, fFrame = pinFootView.frame
let offsetHeight1 = fFrame.height * 0.7
let offsetHeight2 = fFrame.height * 0.1
let hFrame1 = CGRect.init(origin: CGPoint.init(x: hFrame.origin.x, y: hFrame.origin.y - offsetHeight1), size: hFrame.size)
let fFrame1 = CGRect.init(x: fFrame.origin.x, y: fFrame.origin.y - offsetHeight1, width: fFrame.width, height: fFrame.height + offsetHeight1)
let hFrame2 = CGRect.init(origin: CGPoint.init(x: hFrame.origin.x, y: hFrame.origin.y - offsetHeight2), size: hFrame.size)
let fFrame2 = CGRect.init(x: fFrame.origin.x, y: fFrame.origin.y - offsetHeight2, width: fFrame.width, height: fFrame.height * 0.2)
let hFrame3 = CGRect.init(origin: CGPoint.init(x: hFrame.origin.x, y: hFrame.origin.y + fFrame.height * 0.7), size: hFrame.size)
let fFrame3 = CGRect.init(x: fFrame.origin.x, y: fFrame.origin.y + 0.7 * fFrame.height, width: fFrame.width, height: fFrame.height * 0.3)
UIView.animate(withDuration: 0.1, delay: 0, options: .curveEaseOut, animations: {
self.pinHeadView.frame = hFrame1
self.pinFootView.frame = fFrame1
}) { (complete) in
UIView.animate(withDuration: 0.1, delay: 0, options: .curveLinear, animations: {
self.pinHeadView.frame = hFrame2
self.pinFootView.frame = fFrame2
}, completion: { (complete) in
UIView.animate(withDuration: 0.1, delay: 0, options: .curveEaseOut, animations: {
self.pinHeadView.frame = hFrame3
self.pinFootView.frame = fFrame3
}, completion: {(complete) in
UIView.animate(withDuration: 0.12, delay: 0,options: .curveEaseOut, animations: {
self.pinHeadView.frame = hFrame
self.pinFootView.frame = fFrame
}, completion:{(complete) in
if rhythmNeed {
self.rhythm()
}
})
})
})
}
具体的实现在 -> SRPinView里面,直接用的UIView的animation封装,没有使用CABasicAnimation系列的动画,其实用那种也可以实现,只是得通过CASharpLayer绘制UIBezierPath等等,由于大头针跳动动画,只用到位移,而没有用到变形这些,所以也没必要上CA系列。
使用
项目用的是Swift,可以直接去项目地址下载,也可以使用cocoapods安装,能帮到你的话,请给星支持!$_^(感激脸)
use_frameworks!
pod 'SRPinView'

创建SRPinView和调用
- 代码init
-
在Storyboard中创建一个View,然后设置Class和约束中设置宽高,建议将高度设置为宽度的2倍左右
设置class.png

- 调用
// rhythm 参数 ,true 表示跳动完成后,底部圆圈放大的律动效果
// false 完成后不做动画
self.pinView.jump(rhythmNeed: true)
至此,我们可以愉快的在地图里跳跃了。
网友评论