动画`uIView`的`backgroundColor`实现`drawRect`

时间:2015-03-05 11:13:03

标签: ios swift uiview uiviewanimation

我有自定义UIView,我想为其backgroundColor属性设置动画。这是UIView的{​​{3}}。

这是代码:

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

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

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

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

3 个答案:

答案 0 :(得分:4)

当我尝试它时确实不起作用,我有一个相关的问题,即在动画中放置layoutIfNeeded()方法并使视图平滑地动画化(move button towards target using constraints, no reaction?)。但在这种情况下,使用backgroundColor,它不起作用。如果有人知道答案我会有兴趣知道。

但是如果你现在需要一个解决方案,你可以创建一个仅用作容器的UIView(以编程方式或通过故事板)。然后在里面添加2个视图:一个在顶部,一个在下面,与容器具有相同的框架。并且您只更改顶视图的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")
        }
    }
}

答案 1 :(得分:2)

答案是,您无法为实现backgroundColor的视图的drawRect设置动画。我没有在任何地方看到这方面的文件(如果你知道一个,请发表评论)。

您无法使用animateWithDuration或Core Animation为其设置动画。

This thread有我发现的最佳解释:

  

当您实现-drawRect:时,视图的背景颜色会被绘制到关联的CALayer中,而不是仅仅作为样式属性在CALayer上设置...从而阻止您获取内容交叉渐变

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

会喜欢很好地理解为什么会这样,以及为什么它会默默地吞下动画而不是大喊大叫。

答案 2 :(得分:1)

不确定这是否适合您,但为了给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