Swift - Color fill animation

守給你的承諾、 提交于 2019-12-01 04:29:27

The error part of the problem seems to be this part of the code:

cell.pageBadgeView.drawRect(frame)

From the Apple docs on UIView drawRect:

This method is called when a view is first displayed or when an event occurs that invalidates a visible part of the view. You should never call this method directly yourself. To invalidate part of your view, and thus cause that portion to be redrawn, call the setNeedsDisplay or setNeedsDisplayInRect: method instead.

So if you'd change your code to:

cell.pageBadgeView.setNeedsDisplay() 

You'll get rid of the error and see the badgeView filled correctly. However this won't animate it, since drawRect isn't animatable by default.

The easiest workaround to your problem would be for BadgeView to have an internal view for the fill color. I'd refactor the BadgeView as so:

class BadgeView: UIView {

    private let fillView = UIView(frame: CGRectZero)

    private var coeff:CGFloat = 0.5 {
        didSet {
            // Make sure the fillView frame is updated everytime the coeff changes
            updateFillViewFrame()
        }
    }

    // Only needed if view isn't created in xib or storyboard
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    // Only needed if view isn't created in xib or storyboard
    override init(frame: CGRect) {
        super.init(frame: frame)

        setupView()
    }

    override func awakeFromNib() {
        setupView()
    }

    private func setupView() {
        // Setup the layer
        layer.cornerRadius = bounds.height/2.0
        layer.masksToBounds = true

        // Setup the unfilled backgroundColor
        backgroundColor = UIColor(red: 249.0/255.0, green: 163.0/255.0, blue: 123.0/255.0, alpha: 1.0)

        // Setup filledView backgroundColor and add it as a subview
        fillView.backgroundColor = UIColor(red: 252.0/255.0, green: 95.0/255.0, blue: 95.0/255.0, alpha: 1.0)
        addSubview(fillView)

        // Update fillView frame in case coeff already has a value
        updateFillViewFrame()
    }

    private func updateFillViewFrame() {
        fillView.frame = CGRectMake(0, bounds.height*(1-coeff), bounds.width, bounds.height*coeff)
    }

    // Setter function to set the coeff animated. If setting it not animated isn't necessary at all, consider removing this func and animate updateFillViewFrame() in coeff didSet
    func setCoeff(coeff: CGFloat, animated: Bool) {
        if animated {
            UIView.animateWithDuration(4.0, animations:{ () -> Void in
                self.coeff = coeff
            })
        } else {
            self.coeff = coeff
        }
    }

}

In your button callback you'll just have to do:

cell.pageBadgeView.setCoeff(1.0, animated: true)

try this playground code

import UIKit
import CoreGraphics

var str = "Hello, playground"

class BadgeView: UIView {

    var coeff:CGFloat = 0.5

    func drawCircleInView(){
    // Set up the shape of the circle
        let size:CGSize = self.bounds.size;
        let layer = CALayer();
        layer.frame = self.bounds;
        layer.backgroundColor = UIColor.blue().cgColor



        let initialRect:CGRect = CGRect.init(x: 0, y: size.height, width: size.width, height: 0)

        let finalRect:CGRect = CGRect.init(x: 0, y: size.height/2, width: size.width, height: size.height/2)

        let sublayer = CALayer()
        sublayer.frame = initialRect
        sublayer.backgroundColor = UIColor.orange().cgColor
        sublayer.opacity = 0.5


        let mask:CAShapeLayer = CAShapeLayer()
        mask.frame = self.bounds
        mask.path = UIBezierPath(ovalIn: self.bounds).cgPath
        mask.fillColor = UIColor.black().cgColor
        mask.strokeColor = UIColor.yellow().cgColor

        layer.addSublayer(sublayer)
        layer.mask = mask

        self.layer.addSublayer(layer)

        let boundsAnim:CABasicAnimation  = CABasicAnimation(keyPath: "bounds")
        boundsAnim.toValue = NSValue.init(cgRect:finalRect)

        let anim = CAAnimationGroup()
        anim.animations = [boundsAnim]
        anim.isRemovedOnCompletion = false
        anim.duration = 3
        anim.fillMode = kCAFillModeForwards
        sublayer.add(anim, forKey: nil)
    }
}

var badgeView:BadgeView = BadgeView(frame:CGRect.init(x: 50, y: 50, width: 50, height: 50))
var window:UIWindow = UIWindow(frame: CGRect.init(x: 0, y: 0, width: 200, height: 200))
window.backgroundColor = UIColor.red()
badgeView.backgroundColor = UIColor.green()
window.becomeKey()
window.makeKeyAndVisible()
window.addSubview(badgeView)
badgeView.drawCircleInView()

More Modification to Above code , anchor point code was missing in above code

   ```
    var str = "Hello, playground"

 class BadgeView: UIView {

var coeff:CGFloat = 0.7

func drawCircleInView(){
    // Set up the shape of the circle
    let size:CGSize = self.bounds.size;

    let layerBackGround = CALayer();
    layerBackGround.frame = self.bounds;
    layerBackGround.backgroundColor = UIColor.blue.cgColor
   self.layer.addSublayer(layerBackGround)


    let initialRect:CGRect = CGRect.init(x: 0, y: size.height , width: size.width, height: 0)

    let finalRect:CGRect = CGRect.init(x: 0, y: 0, width: size.width, height:  size.height)

    let sublayer = CALayer()
    //sublayer.bounds = initialRect
    sublayer.frame = initialRect
    sublayer.anchorPoint = CGPoint(x: 0.5, y: 1)
    sublayer.backgroundColor = UIColor.orange.cgColor
    sublayer.opacity = 1


    let mask:CAShapeLayer = CAShapeLayer()
    mask.frame = self.bounds
    mask.path = UIBezierPath(ovalIn: self.bounds).cgPath
    mask.fillColor = UIColor.black.cgColor
    mask.strokeColor = UIColor.yellow.cgColor

    layerBackGround.addSublayer(sublayer)
    layerBackGround.mask = mask

    self.layer.addSublayer(layerBackGround)

    let boundsAnim:CABasicAnimation  = CABasicAnimation(keyPath: "bounds")
    boundsAnim.toValue = NSValue.init(cgRect:finalRect)

    let anim = CAAnimationGroup()
    anim.animations = [boundsAnim]
    anim.isRemovedOnCompletion = false
    anim.duration = 1
    anim.fillMode = kCAFillModeForwards
    sublayer.add(anim, forKey: nil)
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!