为实现“drawRect”的“UIView”的“backgroundColor”制作动画



我有一个自定义的UIView,我想为它的backgroundColor属性设置动画。这是UIView的可设置动画的属性。

这是代码:

class ETTimerUIView: UIView {
  required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
  }
  // other methods
  func flashBg() {
    UIView.animateWithDuration( 1.0, animations: {
      self.backgroundColor = UIColor.colorYellow()
    })
  }
  override func drawRect() {
    // Something related to a timer I'm rendering
  }

此代码导致动画跳过,颜色立即更改:

self.backgroundColor = UIColor.colorYellow() // Changes immediately to yellow

如果我为alpha设置动画,这将在一秒钟内按预期从1到0设置动画:

self.alpha = 0 // animates

在这种情况下,如何设置背景颜色变化的动画?

  • 实现drawRect阻止backgroundColor动画,但还没有提供答案
  • 也许这就是为什么你不能把drawRectanimateWithDuration结合起来,但我不太理解

我想我需要制作一个单独的视图——这应该放在同一个视图控制器的故事板中吗?以编程方式创建?

对不起,我真的是iOS和Swift的新手。

当我尝试它时,它确实不起作用,我有一个相关的问题,在动画中放置layoutIfNeedd()方法在哪里起作用,并使视图平滑地设置动画(使用约束将按钮移向目标,没有反应?)。但在这种情况下,使用backgroundColor是不起作用的。如果有人知道答案,我很想知道。

但是,如果您现在需要一个解决方案,您可以创建一个UIView(以编程方式或通过情节提要),它仅用作容器。然后在里面添加两个视图:一个在上面,一个在下面,框架与容器相同。您只需更改顶部视图的alpha,即可让用户看到后面的视图:

class MyView : UIView {
    var top : UIView!
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.backgroundColor = UIColor.blueColor()
        top = UIView(frame: CGRectMake(0,0, self.frame.width, self.frame.height))
        top.backgroundColor = UIColor.yellowColor()
        self.addSubview(top)
    }
    override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
        let sub = UIView(frame: CGRectMake(0,0, self.frame.width, self.frame.height))
        sub.backgroundColor = UIColor.purpleColor()
        self.sendSubviewToBack(sub)
        UIView.animateWithDuration(1, animations: { () -> Void in
            self.top.alpha = 0
            }) { (success) -> Void in
                println("anim finished")
        }
    }
}

答案是,不能为实现drawRect的视图的backgroundColor设置动画。我在任何地方都看不到这方面的文档(如果你知道的话,请评论)。

不能使用animateWithDuration或"核心动画"设置它的动画。

这个帖子有我发现的最好的解释:

当您实现-drawRect:时,视图的背景色将被绘制到关联的CALayer中,而不仅仅是在CALayer上设置为样式属性。。。从而防止您获得内容交叉的

正如@Paul所指出的,解决方案是在上面、后面或任何地方添加另一个视图,并将其设置为动画。这个动画效果很好。

我希望能很好地理解为什么它会这样,为什么它会默默地吞下动画而不是大喊大叫。

不确定这是否适用于您,但为了使UIView的背景色动画化,我将其添加到UIView扩展中:

extension UIView {
    /// Pulsates the color of the view background  to white.
    ///
    /// Set the number of times the animation should repeat, or pass
    /// in `Float.greatestFiniteMagnitude` to pulsate endlessly.
    /// For endless animations, you need to manually remove the animation.
    ///
    /// - Parameter count: The number of times to repeat the animation.
    ///
    func pulsate(withRepeatCount count: Float = 1) {
        let pulseAnimation = CABasicAnimation(keyPath: "backgroundColor")
        pulseAnimation.fromValue = <#source UIColor#>.cgColor
        pulseAnimation.toValue = <#target UIColor#>.cgcolor
        pulseAnimation.duration = 0.4
        pulseAnimation.autoreverses = true
        pulseAnimation.repeatCount = count
        pulseAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
        self.layer.add(pulseAnimation, forKey: "Pulsate")
        CATransaction.commit()
    }
}

将其粘贴到Xcode中的源文件时,请将占位符替换为所需的两种颜色。或者,您可以用以下值替换整行:

pulseAnimation.fromValue = backgroundColor?.cgColor
pulseAnimation.toValue = UIColor.white.cgColor

最新更新