2016-07-19 3 views
0

Я хочу, чтобы слой вести себя так:CABasicAnimation запускается после неявных анимации

correct

Вместо этого, он ведет себя так:

improper

карта покадровая анимация создается два CABasicAnimation s применяется в 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) 
    } 
} 
+0

Я на самом деле не положителен, если 'setValue (_: forKeyPath:)' контролируется Core Animation для активации неявных анимаций или нет. Если вы окружаете эти два вызова функций с помощью ['CATransaction', который отключает действия] (http://calayer.com/core-animation/2016/05/17/catransaction-in-depth.html#preventing-animations-from-), это устраняет проблему? – LucasTizma

+0

Спасибо, @LucasTizma! Это был правильный код. Я описал его полностью в ответе ниже. –

+1

Я получил нижний предел по исходному вопросу, так что теперь значение равно «-1». Я не уверен, почему я получил понижение. Если бы downvoter мог прокомментировать, я был бы рад ответить на его или ее беспокойство. Это не такой конкретный случай использования, как может показаться. Этот вопрос в целом применим. Если вы не добавите код для отключения неявной анимации, CAAnimationGroup не будет вести себя так, как ожидалось. –

ответ

1

@ У Лукаса Тизма был правильный ответ.

Окружающая среда с 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() 
    } 
} 
+0

Рад, что это сработало! В качестве побочной заметки вы должны уметь исправлять эти псевдонимы, растеризуя слой (и устанавливая масштаб растеризации в масштабе основного экрана) во время анимации. – LucasTizma

+0

Спасибо @ LucasTizma. Это тоже хорошо работает! Я добавил код для гладкого сглаживания ответа. –

+0

В идеале вы просто растеризуете во время анимации и отключите его после. Вы снова можете использовать транзакции [знать, когда все анимации сделаны] (http://calayer.com/core-animation/2016/05/17/catransaction-in-depth.html#getting-notified-when-animations -finish), чтобы вы могли отключить растрирование. – LucasTizma

-1

Вы создаете 2 отдельные анимации и применения их в анимации группы. Когда вы это делаете, они применяются как два дискретных шага.

Похоже, это не то, что вы хотите. Если нет, то не создавайте две отдельные анимации, одну на transform.rotation.x, а другую на transform.rotation.y. Вместо этого объедините оба изменения в матрицу преобразования и примените измененную матрицу преобразования как одну анимацию.

+0

С вашей обратной связью, я пробовал этот код, но он по-прежнему не прав: https://gist.github.com/benmorrow/174e4f16053ac979ed62cee0d82c9560 –

+0

Попробуйте применить сначала поворот PI вокруг x, а затем поворот PI вокруг y, к преобразованию. Это не то же самое, что вращение PI вдоль линии 1,1,0 до 0,0,0. –

+0

Да, вы были правы. Этот эффект почти отсутствует. Я обновил Gist из предыдущего комментария, если вы хотите увидеть новый код.Однако эффект, который я ищу, все еще не существует, потому что генерируемая анимация эквивалентна вращению вокруг оси z. Вот что из этого: http://i.imgur.com/FpQMOHy.gifv Я ищу лицевую грань на лицевой стороне, как в первом GIF, в главном вопросе –