为了获得飞机在给定的 pct 值下的 x 和 y 位置,可以使用 Path 结构体的 .trimmedPath() 修饰符,给定一个起点和终点百分比,该方法返回一个 CGRect,它包含了该段路径的边界。
根据我们的需求,只需用使用非常接近的起点和终点来调用它,它将返回一个非常小的矩形,将使用其中心作为 X 和 Y 位置。
funcpercentPoint(_ percent:CGFloat)->CGPoint{// percent difference between pointslet diff:CGFloat=0.001let comp:CGFloat=1- diff
// handle limitslet pct = percent >1?0:(percent <0?1: percent)let f = pct > comp ? comp : pct
let t = pct > comp ?1: pct + diff
let tp = path.trimmedPath(from: f, to: t)returnCGPoint(x: tp.boundingRect.midX, y: tp.boundingRect.midY)}
② 寻找方向
为了获得平面的旋转角度,需要使用一点三角函数,使用上面描述的技术,将得到两点的 X 和 Y 的位置:当前位置和刚才的位置,通过创建一条假想线,可以计算出它的角度,这就是飞机的方向:
funccalculateDirection(_ pt1:CGPoint,_ pt2:CGPoint)->CGFloat{let a = pt2.x - pt1.x
let b = pt2.y - pt1.y
let angle = a <0?atan(Double(b / a)):atan(Double(b / a))-Double.pi
returnCGFloat(angle)}
③ 把所有的内容结合在一起
知道实现目标所需的工具,我们来实现这种效果:
structFollowEffect:GeometryEffect{var pct:CGFloat=0let path:Pathvar rotate =truevar animatableData:CGFloat{get{return pct }set{ pct = newValue }}funceffectValue(size:CGSize)->ProjectionTransform{if!rotate {// Skip rotation loginlet pt =percentPoint(pct)returnProjectionTransform(CGAffineTransform(translationX: pt.x, y: pt.y))}else{let pt1 =percentPoint(pct)let pt2 =percentPoint(pct -0.01)let angle =calculateDirection(pt1, pt2)let transform =CGAffineTransform(translationX: pt1.x, y: pt1.y).rotated(by: angle)returnProjectionTransform(transform)}}funcpercentPoint(_ percent:CGFloat)->CGPoint{// percent difference between pointslet diff:CGFloat=0.001let comp:CGFloat=1- diff
// handle limitslet pct = percent >1?0:(percent <0?1: percent)let f = pct > comp ? comp : pct
let t = pct > comp ?1: pct + diff
let tp = path.trimmedPath(from: f, to: t)returnCGPoint(x: tp.boundingRect.midX, y: tp.boundingRect.midY)}funccalculateDirection(_ pt1:CGPoint,_ pt2:CGPoint)->CGFloat{let a = pt2.x - pt1.x
let b = pt2.y - pt1.y
let angle = a <0?atan(Double(b / a)):atan(Double(b / a))-Double.pi
returnCGFloat(angle)}}
Returns an effect producing the same geometry transform as “self” but that will only be applied while rendering its view, not while the view is performing its layout calculations.Thisis often used to disable layout changes during transitions, but that will only be applied while rendering its view, not while the view is performing its layout calculations.Thisis often used to disable layout changes during transitions.