如何从CAMediaTimingFunction获取指定时间点的进度值?
该需求可以实现。
你使用的CAMediaTimingFunction本质是定义了一条起点为(0,0)、终点为(1,1)的三次贝塞尔曲线,其中x轴对应[0,1]区间的输入时间,y轴对应[0,1]区间的输出进度。系统没有直接提供通过CAMediaTimingFunction实例直接传入时间求进度的API,但可以通过手动求解三次贝塞尔曲线的方式实现需求。
你给出的easeInQuart对应控制点定义如下:
let timingFunction = CAMediaTimingFunction(controlPoints: 0.895, 0.03, 0.685, 0.22)
你可以直接使用以下Swift代码实现求值逻辑:
/// 求解easeInQuart缓动曲线对应的输出进度 /// - Parameter x: 输入时间,取值范围[0,1] /// - Returns: 输出进度,取值范围[0,1] func getEaseInQuartProgress(for x: CGFloat) -> CGFloat { let epsilon: CGFloat = 1e-6 // 曲线两个控制点参数 let cp1x: CGFloat = 0.895, cp1y: CGFloat = 0.03 let cp2x: CGFloat = 0.685, cp2y: CGFloat = 0.22 // 给定参数t,求贝塞尔曲线的x值 func sampleX(t: CGFloat) -> CGFloat { let t2 = t * t, t3 = t2 * t let mt = 1 - t, mt2 = mt * mt, mt3 = mt2 * mt return 3 * cp1x * mt2 * t + 3 * cp2x * mt * t2 + t3 } // 给定参数t,求贝塞尔曲线的y值 func sampleY(t: CGFloat) -> CGFloat { let t2 = t * t, t3 = t2 * t let mt = 1 - t, mt2 = mt * mt, mt3 = mt2 * mt return 3 * cp1y * mt2 * t + 3 * cp2y * mt * t2 + t3 } // 求x对t的导数,用于牛顿迭代快速收敛 func derivativeX(t: CGFloat) -> CGFloat { let t2 = t * t let mt = 1 - t, mt2 = mt * mt return 3 * cp1x * (mt2 - 2 * mt * t) + 3 * cp2x * (2 * mt * t - t2) + 3 * t2 } // 牛顿迭代求解对应输入x的参数t var t = x for _ in 0..<8 { let currentX = sampleX(t: t) guard abs(currentX - x) > epsilon else { break } let dx = derivativeX(t: t) guard abs(dx) >= 1e-6 else { break } t -= (currentX - x) / dx } return sampleY(t: t) } // 测试用例 let inputTime: CGFloat = 0.5 let outputProgress = getEaseInQuartProgress(for: inputTime) // 计算结果约为0.09,符合easeInQuart初始速度慢、输出值小于输入时间的预期
如果需要实现通用的任意CAMediaTimingFunction求值能力,可以通过系统提供的getControlPoint(at:values:)方法取出实例的两个控制点参数,再代入上述逻辑即可。
内容的提问来源于stack exchange,提问作者Mac
相关产品推荐
相关产品推荐

