CABasicAnimation 在隐式动画之后运行

CABasicAnimation runs after Implicit Animation

我希望图层的行为如下:

相反,它的行为如下:

卡片翻转动画是由应用在 CAAnimationGroup 中的两个 CABasicAnimation 创建的。发生不正确的旋转效果是因为 CALayer 属性 更改中的隐式动画首先运行,然后我在 CABasicAnimation 中指定的动画运行。如何停止 运行 中的隐式动画,以便只运行我指定的动画?

相关代码如下:

class ViewController: UIViewController {

  var simpleLayer = CALayer()

  override func viewDidLoad() {
    super.viewDidLoad()

    let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap))
    self.view.addGestureRecognizer(tap)

    simpleLayer.frame = CGRect(origin: CGPoint(x: view.bounds.width / 2 - 50, y: view.bounds.height / 2 - 50), size: CGSize(width: 100, height: 100))
    simpleLayer.backgroundColor = UIColor.blackColor().CGColor
    view.layer.addSublayer(simpleLayer)
  }

  func handleTap() {
    let xRotation = CABasicAnimation(keyPath: "transform.rotation.x")
    xRotation.toValue = 0
    xRotation.byValue = M_PI

    let yRotation = CABasicAnimation(keyPath: "transform.rotation.y")
    yRotation.toValue = 0
    yRotation.byValue = M_PI

    simpleLayer.setValue(M_PI, forKeyPath: "transform.rotation.y")
    simpleLayer.setValue(M_PI, forKeyPath: "transform.rotation.x")

    let group = CAAnimationGroup()
    group.animations = [xRotation, yRotation]
    group.duration = 0.6
    group.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
    simpleLayer.addAnimation(group, forKey: nil)
  }
}

您正在创建 2 个单独的动画并将它们应用到一个动画组中。当您这样做时,它们将作为 2 个离散步骤应用。

看来这不是你想要的。如果不是,则不要创建 2 个单独的动画,一个在 transform.rotation.x 上,另一个在 transform.rotation.y 上。相反,将两个更改连接到转换矩阵并将更改的转换矩阵应用为单个动画。

@LucasTizma 的答案是正确的。

CATransaction.begin(); CATransaction.setDisableActions(true)CATransaction.commit() 包围您的动画。这将 disable the implicit animation 并使 CAAnimationGroup 正确动画。

这是最终结果:

这是Swift 3:

中的重要代码片段
CATransaction.begin()
CATransaction.setDisableActions(true)

let xRotation = CABasicAnimation(keyPath: "transform.rotation.x")
xRotation.toValue = 0
xRotation.byValue = M_PI

let yRotation = CABasicAnimation(keyPath: "transform.rotation.y")
yRotation.toValue = 0
yRotation.byValue = M_PI

simpleLayer.setValue(M_PI, forKeyPath: "transform.rotation.x")
simpleLayer.setValue(M_PI, forKeyPath: "transform.rotation.y")

let group = CAAnimationGroup()
group.animations = [xRotation, yRotation]
simpleLayer.add(group, forKey: nil)

CATransaction.commit()

这是带有 iOS 应用程序的所描绘动画的完整代码:

class ViewController: UIViewController {

  var simpleLayer = CALayer()

  override func viewDidLoad() {
    super.viewDidLoad()

    let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap))
    self.view.addGestureRecognizer(tap)

    let ratio: CGFloat = 1 / 5
    let viewWidth = view.bounds.width
    let viewHeight = view.bounds.height
    let layerWidth = viewWidth * ratio
    let layerHeight = viewHeight * ratio

    let rect = CGRect(origin: CGPoint(x: viewWidth / 2 - layerWidth / 2,
                                      y: viewHeight / 2 - layerHeight / 2),
                      size: CGSize(width: layerWidth, height: layerHeight))

    let topRightPoint = CGPoint(x: rect.width, y: 0)
    let bottomRightPoint = CGPoint(x: rect.width, y: rect.height)
    let topLeftPoint = CGPoint(x: 0, y: 0)

    let linePath = UIBezierPath()

    linePath.move(to: topLeftPoint)
    linePath.addLine(to: topRightPoint)
    linePath.addLine(to: bottomRightPoint)
    linePath.addLine(to: topLeftPoint)

    let maskLayer = CAShapeLayer()
    maskLayer.path = linePath.cgPath

    simpleLayer.frame = rect
    simpleLayer.backgroundColor = UIColor.black.cgColor
    simpleLayer.mask = maskLayer

    // Smooth antialiasing
    // * Convert the layer to a simple bitmap that's stored in memory
    // * Saves CPU cycles during complex animations
    // * Rasterization is set to happen during the animation and is disabled afterwards
    simpleLayer.rasterizationScale = UIScreen.main.scale

    view.layer.addSublayer(simpleLayer)
  }

  func handleTap() {
    CATransaction.begin()
    CATransaction.setDisableActions(true)
    CATransaction.setCompletionBlock({
      self.simpleLayer.shouldRasterize = false
    })

    simpleLayer.shouldRasterize = true

    let xRotation = CABasicAnimation(keyPath: "transform.rotation.x")
    xRotation.toValue = 0
    xRotation.byValue = M_PI

    let yRotation = CABasicAnimation(keyPath: "transform.rotation.y")
    yRotation.toValue = 0
    yRotation.byValue = M_PI

    simpleLayer.setValue(M_PI, forKeyPath: "transform.rotation.x")
    simpleLayer.setValue(M_PI, forKeyPath: "transform.rotation.y")

    let group = CAAnimationGroup()
    group.animations = [xRotation, yRotation]
    group.duration = 1.2
    group.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
    simpleLayer.add(group, forKey: nil)

    CATransaction.commit()
  }
}