iOS-QQ.badge
2018-10-25 本文已影响0人
NiSY
1. 拆分
① 拖拽移动badge
② badge原位置留下一个相同center
的圆,圆半径随拖拽距离增大而减小
③ 两圆之间有一条牵引线,线的腰部随拖拽距离增大而收窄
④ 拖动距离小于某值,松开badge,badge返回原位置,有一个抖动和缩放动画
⑤ 拖动距离大于某值,badge消失
2. 关键动画实现

dis
(拖动距离)是影响动画表现的关键参数:
let dis = sqrtf(powf(Float(circleCenter.x - badgeCenter.x), 2) + powf(Float(circleCenter.y - badgeCenter.y), 2))
根据β角三角函数结合半径,求出ABCD四点坐标
let cos = Float(badgeCenter.y - circleCenter.y) / dis
let sin = Float(badgeCenter.x - circleCenter.x) / dis
let circlePointA = CGPoint(x: circleCenter.x - CGFloat(cirlceR * cos) , y: circleCenter.y + CGFloat(cirlceR * sin))
let circlePointB = CGPoint(x: circleCenter.x + CGFloat(cirlceR * cos) , y: circleCenter.y - CGFloat(cirlceR * sin))
let badgePointC = CGPoint(x: badgeCenter.x + CGFloat(badgeR * cos), y: badgeCenter.y - CGFloat(badgeR * sin))
let badgePointD = CGPoint(x: badgeCenter.x - CGFloat(badgeR * cos), y: badgeCenter.y + CGFloat(badgeR * sin))
选择指数函数来表现腰部随距离拉长而收窄的效果
let controlPointArgument: Float = powf(0.1, dis / 200)
let circlePointMutativeA = CGPoint(x: circleCenter.x - CGFloat(cirlceR * cos * controlPointArgument) , y: circleCenter.y + CGFloat(cirlceR * sin * controlPointArgument))
let circlePointMutativeB = CGPoint(x: circleCenter.x + CGFloat(cirlceR * cos * controlPointArgument) , y: circleCenter.y - CGFloat(cirlceR * sin * controlPointArgument))
o&p点为贝塞尔曲线的控制点
let pointO = CGPoint(x: circlePointMutativeA.x + CGFloat(dis / 2 * sin), y: circlePointMutativeA.y + CGFloat(dis / 2 * cos))
let pointP = CGPoint(x: circlePointMutativeB.x + CGFloat(dis / 2 * sin), y: circlePointMutativeB.y + CGFloat(dis / 2 * cos))
最后使用CAShapeLayer
绘制图形
let path = UIBezierPath()
path.move(to: circlePointA)
path.addLine(to: circlePointB)
path.addQuadCurve(to: badgePointC, controlPoint: pointP)
path.addLine(to: badgePointD)
path.addQuadCurve(to: circlePointA, controlPoint: pointO)
path.close()
shapeLayer.path = path.cgPath
抖动动画通过UIView动画实现,调用函数前需要把badge调整到合适位置
badgeView.center = CGPoint(x: circleCenter.x - CGFloat(50 * sin), y: circleCenter.y - CGFloat(50 * cos))
UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 0.2, initialSpringVelocity: 10, options: [], animations: {[weak self] in
if let strongSelf = self {
strongSelf.badgeView.center = strongSelf.redCircle.center
}
}) { (finished) in
}
最后再加上一些简单的消失复位逻辑判断。
