【问题标题】:How to animate only a percentage of the full CALayer animation along a UIBezierPath?如何仅沿 UIBezierPath 为完整 CALayer 动画的一部分设置动画?
【发布时间】:2015-10-05 02:04:32
【问题描述】:

我设法沿 UIBezierPath 为 CALayer 设置动画。

我想要完成的是只为路径的一部分设置动画,例如,只有 25% 的路径,图层保持在该位置(25%)。

这样做的方法是什么?这是我的代码,它总是为完整路径设置动画。

let aPath = UIBizierPath(CGPath: somePath)
let anim = CAKeyframeAnimation(keyPath: "position")
anim.path = aPath.CGPath
anim.rotationMode = kCAAnimationRotateAuto
anim.repeatCount = 1
anim.fillMode = kCAFillModeForwards
anim.removedOnCompletion = false
anim.duration = 3.0
anim.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)

ticker.addAnimation(anim, forKey: "animate_ticker")

【问题讨论】:

    标签: ios caanimation cakeyframeanimation


    【解决方案1】:

    简单更改一个属性:

    anim.repeatCount = 0.25    
    

    这是 excellent article on animation timing,您可以学习如何对动画进行更细粒度的控制。

    追加:
    1.要达到你想要的,最接近的方法是有一个25%的子路径,这里有一些helper method

    2.如果你能忍受速度差,使用上面的方法,在动画结束时设置回位置:

    ticker.position = ticker.presentationLayer().position
    

    【讨论】:

    • 这样做的问题是动画不会在 path 的 1/4 处停止,而只会在 animation 的 1/4 处停止。因此,使用kCAMediaTimingFunctionEaseInEaseOut 计时函数和repeatCount 0.25,动画将比预期的更快停止。此外,计时功能仍将应用于整个动画的持续时间——因此它似乎会加速然后突然停止,这可能是也可能不是 OP 想要的。
    • @originaluser2,你是对的。我发现动画没有完全停在我想的地方,所以这就解释了!谢谢!我正在寻找路径的 1/4,而不是动画。
    【解决方案2】:

    不仅CGPath 是不透明的,而且CAAnimation 不支持正在进行的动画的任何更新或通知(即在开始之后但在完成之前)。唯一涉及的实体是动画本身和它所应用的CALayer-s。

    所以,选项是:

    (有些选项可能听起来太吓人但其实不然,所以我做了一个示例项目,见下文)

    重复次数

    wj2061 提到的是his answer,您可以调整动画的repeatCount。缺点是它将动画 0.25 的动画时间,而不是 0.25 的路径

    CAShapeLayer

    如果有任何机会,您可以用CAShapeLayer 段表示您的ticker,那么您可以为strokeStartstrokeEnd 设置动画,这样段看起来就像沿着路径移动

    聪明的重复计数

    您可以计算出这样的repeatCount 值,动画将在路径的 0.25 处停止。

    • 获取一些贝塞尔库
    • 使用getControlPointAtIndex:从计时函数中提取贝塞尔曲线
    • 求解贝塞尔曲线以获得它的“进度值”(通常命名为t),贝塞尔曲线的“y”值将与您的“所需进度”(0.25)相匹配
    • 计算 t 的贝塞尔曲线“x”值 - 这是您需要的 repeatCount 的准确值

    使用 CAAnimation 制作动画,全部由您自己完成

    有点高级

    • 获取一些贝塞尔库
    • 创建具有动态属性的自定义 CALayer 子类,比如说rideProgress
    • 为贝塞尔路径(来自贝塞尔库,而不是 CGPath)和子层(例如,rideLayer)添加合成属性以进行动画处理
    • 覆盖needsDisplayForKey: 用于rideProgress 键和initWithLayer: 用于所有引入的属性但使用self.rideLayer?.presentationLayer() 而不是复制rideLayer
    • 覆盖其中之一:drawInContext: 并在其中绘制您需要的内容;或(更好)display,在display 中从presentationLayer 检索当前rideProgress 值并更新子层,然后调用super。无论哪种方式,使用贝塞尔库根据当前rideProgress 值计算子层的位置和旋转
    • 在设置任何层的任何动画属性之前不要忘记CATransaction.setDisableActions(true)
    • 最后,在 rideProgress 属性上使用任何类型的 CAAnimation 或隐式动画

    分割路径

    同样,wj2061 建议。您可以拆分路径,使一半代表原始路径的 0.25


    Here 是上面所有内容的示例实现,除了“拆分路径”。我没有对此代码进行任何现场测试,这只是一个工作概念。 XCode 7.3.1,斯威夫特。


    使用的材料:Wiki on Cubic functionGreat article about operations on beziersCubic equations solving method line-by-line

    【讨论】:

      【解决方案3】:

      您是否尝试设置 fromValuetoValue 属性?如果您将 fromValue 设置为 0.0 并将 toValue 设置为 0.25

      ,它应该可以工作

      【讨论】:

      • fromValuetoValueCABasicAnimation 中引入,它不是CAKeyframeAnimation 的超类
      【解决方案4】:

      我遇到了同样的问题,我想为路径的绘制设置动画,但只是其中的一部分。

      我最终将图层的 strokeStart 和 strokeEnd 设置为与动画相同的浮点值。

      因此,在您的示例中,尝试设置anim.fromValue = 0.0f、anim.toValue = 0.6f 以及ticker.strokeStart=0.0fticker.strokeEnd = 0.6f

      这成功地仅绘制了 60% 的路径并对其进行了动画处理!

      【讨论】:

      • 我不记得确切的原因,但这不起作用。 (我不是投反对票的人)
      猜你喜欢
      • 1970-01-01
      • 2012-06-07
      • 1970-01-01
      • 2019-04-18
      • 1970-01-01
      • 2018-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多