CABasicAnimation在Implicit Animation之后运行

时间:2016-07-19 23:20:15

标签: ios swift core-animation calayer cabasicanimation

我希望图层的行为如下:

correct

相反,它的行为如下:

improper

卡片翻转动画由CABasicAnimation中应用的两个CAAnimationGroup创建。发生不正确的旋转效果是因为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 个答案:

答案 0 :(得分:1)

@LucasTizma有正确的答案。

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

这是最终结果:

triangle flip animation

这是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()
  }
}

答案 1 :(得分:-1)

您正在创建2个单独的动画并将其应用于动画组。当你这样做时,他们被应用为两个不连续的步骤。

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