CATransaction:视图在完成时闪烁

CATransaction: a view flashes on completion

我正在编写一个有点复杂的动画,分为 2 个步骤:

  1. 将不需要可见的 UIViews 的不透明度更改为 0,并将 UIImageView(具有 alpha = 1)移动到另一个 CGPoint(位置)。
  2. 把另一个UIView的不透明度改成1,把上一步的UIImageView的不透明度改成0,然后在这一步的动画结束后,去掉UIImageView来自 superview.

我是这样做的:

第一步 是在没有显式 CATransaction 的情况下完成的。这 2 个动画只是将 beginTime 设置为 CACurrentMediaTime()。我在 layer.addAnimation(...) 调用后立即对视图应用更改。 这里一切正常。

第二步实现中我在开头调用了CATransaction.begin()。 在 begin/commitCATransaction 的调用中,我创建了 2 个 CABasicAnimations 并将其添加到 2 个不同的图层:一个用于将不透明度从 0 更改为 1(对于 UIView),另一个用于更改从 1 到 0 的不透明度(UIImageView)。两个动画都将 beginTime 设置为 CACurrentMediaTime() + durationOfThePreviousStep

CATransaction.begin() 之后我立即调用 CATransaction.setCompletionBlock({...}),并在这个完成块中对这两个视图应用更改:设置它们的新 alpha 并从 superview 中删除 UIImageView

问题是,在整个动画结束时,alpha 动画设置为 1 的 UIView 闪烁,这意味着它的 alpha 设置回 0(尽管我在完成块),紧接着完成块执行,它的 alpha 再次上升到 1。

嗯,问题是,如何摆脱这种闪烁?也许这个动画可以用更好的方式来完成?

P.S。我没有使用 UIView 动画,因为我对这些动画的自定义计时功能感兴趣。

编辑 1: 这是代码。我已经删除了 UIImageView alpha 动画,因为它不是真正必要的。

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 和一个带有 4 个子视图的 UIScrollView。我尝试用 timeView (UIImageView) 的快照替换 timeView,但这没有帮助。

编辑 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()

只要看看您的代码,我就期望它会闪烁。为什么?因为您已将 timeView 图层的不透明度从 0 设置为 1,但您尚未将其 设置 为 1(在完成处理程序中除外,这将在稍后发生)。因此,我们将表示层从 0 设置为 1,然后动画结束,显示真实层的不透明度一直为 0。

因此,在您的动画开始之前,将 timeView 的图层的不透明度设置为 1。此外,由于您使用的是延迟 beginTime,因此您需要将动画的 fillMode 设置为 "backwards"

通过将您的测试代码修改为独立的并且看起来像这样,我能够获得良好的结果;有延迟,view淡入,最后没有闪现:

    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。