CATransaction: по завершении мигает вид

Я пишу немного сложную анимацию, которая состоит из 2 шагов:

  1. Изменить непрозрачность до 0 из UIViews которые не должны быть видны и перемещать UIImageView (у которого есть alpha = 1) другому CGPoint (позиция).
  2. Изменить непрозрачность другого UIView 1 и непрозрачность UIImageView от предыдущего шага до 0, а затем после завершения анимации этого шага удалите UIImageView из супервизии.

Я сделал это так:

Первый шаг выполняется без явной CATransaction. Эти 2 анимации просто имеют beginTime установлен в CACurrentMediaTime(), И я применяю изменения к представлениям сразу после layer.addAnimation(...) вызов. Здесь все отлично работает.

На втором этапе реализации я называю CATransaction.begin() в начале. внутри begin/commit звонки в CATransaction Я создаю и добавляю 2 CABasicAnimations до 2 разных слоев: один для изменения непрозрачности от 0 до 1 (для UIView) и один для изменения непрозрачности от 1 до 0 (для UIImageView). Обе анимации имеют beginTime установлен в CACurrentMediaTime() + durationOfThePreviousStep,

И сразу после CATransaction.begin() Я звоню CATransaction.setCompletionBlock({...})и в этом блоке завершения я применяю изменения к этим двум представлениям: установите их новые альфа и удалите UIImageView из супервизии.

Проблема в том, что в конце всей этой анимации UIView у него альфа-анимация мигает до 1, что означает, что его альфа возвращается в 0 (хотя я установил альфа в 1 в блоке завершения), и сразу после этого выполняется блок завершения, и его альфа снова увеличивается до 1.

Ну, вопрос, как избавиться от этой перепрошивки? Может быть, эту анимацию можно сделать лучше?

PS я не пользуюсь UIView анимации, потому что я заинтересован в пользовательских функциях синхронизации для этих анимаций.

РЕДАКТИРОВАТЬ 1: Вот код. Я удалил UIImageView альфа-анимация, потому что это на самом деле не нужно.

var totalDuration: CFTimeInterval = 0.0

// Alpha animations.
let alphaAnimation = CABasicAnimation()
alphaAnimation.keyPath = "opacity"
alphaAnimation.fromValue = 1
alphaAnimation.toValue = 0
alphaAnimation.beginTime = CACurrentMediaTime()
alphaAnimation.duration = 0.15

let alphaAnimationName = "viewsFadeOut"
view1.layer.addAnimation(alphaAnimation, forKey: alphaAnimationName)
view1.alpha = 0

view2.layer.addAnimation(alphaAnimation, forKey: alphaAnimationName)
view2.alpha = 0

view3.layer.addAnimation(alphaAnimation, forKey: alphaAnimationName)
view3.alpha = 0

view4.layer.addAnimation(alphaAnimation, forKey: alphaAnimationName)
view4.alpha = 0

// Image View moving animation.
// Add to total duration.
let rect = /* getting rect */
let newImagePosition = view.convertPoint(CGPoint(x: CGRectGetMidX(rect), y: CGRectGetMidY(rect)), fromView: timeView)

let imageAnimation = CABasicAnimation()
imageAnimation.keyPath = "position"
imageAnimation.fromValue = NSValue(CGPoint: imageView!.layer.position)
imageAnimation.toValue = NSValue(CGPoint: newImagePosition)
imageAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionDefault)
imageAnimation.beginTime = CACurrentMediaTime()
imageAnimation.duration = 0.3

imageView!.layer.addAnimation(imageAnimation, forKey: "moveImage")
imageView!.center = newImagePosition

totalDuration += imageAnimation.duration

// Time View alpha.
CATransaction.begin()
CATransaction.setCompletionBlock {
    self.timeView.alpha = 1
    self.imageView!.removeFromSuperview()
    self.imageView = nil
}

let beginTime = CACurrentMediaTime() + totalDuration
let duration = 0.3

alphaAnimation.fromValue = 0
alphaAnimation.toValue = 1
alphaAnimation.beginTime = beginTime
alphaAnimation.duration = duration
timeView.layer.addAnimation(alphaAnimation, forKey: "timeViewFadeIn")

/* imageView alpha animation is not necessary, so I removed it */

CATransaction.commit()

РЕДАКТИРОВАТЬ 2: кусок кода, который вызывает проблему:

CATransaction.begin()
CATransaction.setCompletionBlock {
    self.timeView.alpha = 1
}

let duration = 0.3

let alphaAnimation = CABasicAnimation()
alphaAnimation.keyPath = "opacity"
alphaAnimation.fromValue = 0.0
alphaAnimation.toValue = 1.0
alphaAnimation.duration = duration
timeView.layer.addAnimation(alphaAnimation, forKey: "timeViewFadeIn")

CATransaction.commit()

Может быть, проблема в том, что timeView имеет UITextField и UIScrollView с 4 подпредставлениями. Я пытался заменить timeView со снимком timeView (UIImageView), но это не помогло.

РЕДАКТИРОВАТЬ 3: Новый код. С этим кодом timeView всегда имеет alpha = 1, и это также оживляет от 0 до 1.

CATransaction.begin()
CATransaction.setCompletionBlock {
    self.imageView!.removeFromSuperview()
    self.imageView = nil
}

let alphaAnimation = CABasicAnimation()
alphaAnimation.keyPath = "opacity"
alphaAnimation.fromValue = 0.0
alphaAnimation.toValue = 1.0
alphaAnimation.duration = 0.3
alphaAnimation.beginTime = beginTime

timeView.layer.addAnimation(alphaAnimation, forKey: "timeViewFadeIn")
timeView.alpha = 1.0
CATransaction.commit()

1 ответ

Решение

Просто глядя на ваш код, я ожидаю, что он будет мигать. Зачем? Потому что у вас есть анимация timeViewНепрозрачность слоя от 0 до 1, но вы не установили его на 1 (кроме обработчика завершения, что произойдет позже). Таким образом, мы анимируем уровень представления от 0 до 1, и затем анимация заканчивается, и обнаруживается, что непрозрачность реального слоя всегда была равна 0.

Итак, установите timeViewНепрозрачность слоя до 1 до начала анимации. Кроме того, так как вы используете задержанный beginTime, вам нужно будет установить анимацию fillMode в "backwards",

Я смог получить хорошие результаты, изменив свой тестовый код, чтобы он был автономным и выглядел следующим образом; есть задержка, вид исчезает, и в конце нет вспышки:

    CATransaction.begin()
    let beginTime = CACurrentMediaTime() + 1.0 // arbitrary, just testing
    let alphaAnimation = CABasicAnimation()
    alphaAnimation.keyPath = "opacity"
    alphaAnimation.fromValue = 0.0
    alphaAnimation.toValue = 1.0
    alphaAnimation.duration = 1.0 // arbitrary, just testing
    alphaAnimation.fillMode = "backwards"
    alphaAnimation.beginTime = beginTime
    timeView.layer.addAnimation(alphaAnimation, forKey: "timeViewFadeIn")
    timeView.layer.opacity = 1.0
    CATransaction.commit()

Есть некоторые другие вещи в вашем коде, которые я нахожу довольно странными. Таким образом, использование блока завершения транзакции несколько рискованно; Я не понимаю, почему вы не даете свою анимацию делегату. Кроме того, вы используете повторно alphaAnimation многократно; Я не могу рекомендовать это. Я бы создал новую CABasicAnimation для каждой анимации на вашем месте.

Другие вопросы по тегам