Itβs hard for me to understand why the animation flickers fromValue toValue after completing my animation block. I know that after the animation finishes, you must set the CALayer values ββto the final state of the animation so that it looks consistent. But no matter what order I call these methods, I always get a flickering result. What I do is draw a checkmark using the biezer path, and after the strokeEnd animation is complete, I fill the checkmark by animating the fillColor property. The checkmark function and the reset checkmark function are activated when the user selects the tableviewcell row with which the flag is associated. Oh, and I use AutoLayout if that matters.
So, Iβm actually interested in a few 1) When the table view cell is displayed, I call the public function shoudSetCheckmarkToCheckedState, which sets the logical value self.userSelectedCheckmark to the isChecked parameter passed to the function. From there, I call [self setNeedsLayout], which launches layoutSubviews and calls the shouldDrawCheckmark function .... The reason why I do this is that if I'm not the first time the cell is drawn, there is no frame, so my picture looks messy . So I have to call setNeedsLayout every time I change the userSelectedCheckmark property or there is a better way.
2) Why the checkmark flickers after the animation is completed. I think I know why, because when the animation completes the properties of the layers, reset refers to the same state they were in when the layer started the animation. So how can I fix this? I just start the timer to change the fill color by a millisecond before the animation ends, but that doesn't seem right.
heres btw code
typedef void (^animationCompletionBlock)(void); #define kAnimationCompletionBlock @"animationCompletionBlock" #import "CheckmarkView.h" #import "UIColor+HexString.h" @interface CheckmarkView() @property (nonatomic,strong) CAShapeLayer *checkmarkLayer; @property (nonatomic,assign) BOOL userSelectedCheckmark; - (void)shouldDrawCheckmarkToLayerWithAnimation:(BOOL)animateCheckmark; @end @implementation CheckmarkView #pragma mark - Lifecycle /**********************/ - (id)initWithFrame:(CGRect)frame{ self = [super initWithFrame:frame]; if (self) { self.translatesAutoresizingMaskIntoConstraints = FALSE; self.layer.cornerRadius = 5.0; [self setClipsToBounds:TRUE]; } return self; } - (void)layoutSubviews{ [self shouldDrawCheckmarkToLayerWithAnimation:self.userSelectedCheckmark]; } #pragma mark - Public Methods /***************************/ - (void)shouldSetCheckmarkToCheckedState:(BOOL)isChecked{ self.userSelectedCheckmark = isChecked; [self setNeedsLayout]; } #pragma mark - Private Methods /****************************/ - (void)shouldDrawCheckmarkToLayerWithAnimation:(BOOL)animateCheckmark{ if(self.userSelectedCheckmark){ CGRect superlayerRect = self.bounds; if(!self.checkmarkLayer){ self.checkmarkLayer = [CAShapeLayer layer]; [self.checkmarkLayer setStrokeColor:[UIColor whiteColor].CGColor]; UIBezierPath *checkMarkPath = [UIBezierPath bezierPath]; //Start Point [checkMarkPath moveToPoint:CGPointMake(CGRectGetMinX(superlayerRect) + 5, CGRectGetMinY(superlayerRect) + 14)]; //Bottom Point [checkMarkPath addLineToPoint:CGPointMake(CGRectGetMidX(superlayerRect), CGRectGetMaxY(superlayerRect) - 4)]; //Top Right of self.checkmarkLayer [checkMarkPath addLineToPoint:CGPointMake(CGRectGetMaxX(superlayerRect) - 5, CGRectGetMinY(superlayerRect) + 8)]; [checkMarkPath addLineToPoint:CGPointMake(checkMarkPath.currentPoint.x - 3, checkMarkPath.currentPoint.y - 4)]; //Top Middle Point [checkMarkPath addLineToPoint:CGPointMake(CGRectGetMidX(superlayerRect) - 1, CGRectGetMidY(superlayerRect) + 2)]; //Top left of self.checkmarkLayer [checkMarkPath addLineToPoint:CGPointMake(CGRectGetMinX(superlayerRect) + 7, CGRectGetMinY(superlayerRect) + 10)]; [checkMarkPath closePath]; [self.checkmarkLayer setPath:checkMarkPath.CGPath]; } self.layer.backgroundColor = [UIColor colorWithHexString:UIColorOrangeB0].CGColor; [self.checkmarkLayer setFillColor:[UIColor colorWithHexString:UIColorOrangeB0].CGColor]; [self.layer addSublayer:self.checkmarkLayer]; if(animateCheckmark){ animationCompletionBlock block; block = ^(void){ [self.checkmarkLayer setFillColor:[UIColor whiteColor].CGColor]; }; CABasicAnimation *strokeAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; [strokeAnimation setBeginTime:0.0]; [strokeAnimation setFromValue:@(0.0f)]; [strokeAnimation setToValue:@(1.0f)]; [strokeAnimation setDuration:.8]; CABasicAnimation *fillAnimation = [CABasicAnimation animationWithKeyPath:@"fillColor"]; [fillAnimation setBeginTime:strokeAnimation.duration + .2]; [fillAnimation setDuration:.2]; [fillAnimation setFromValue:(id)[UIColor colorWithHexString:UIColorOrangeB0].CGColor]; [fillAnimation setToValue:(id)[UIColor whiteColor].CGColor]; CAAnimationGroup *group = [CAAnimationGroup animation]; group.delegate = self; [group setDuration:1.5]; [group setAnimations:@[strokeAnimation,fillAnimation]]; [group setValue:block forKey:kAnimationCompletionBlock]; [self.checkmarkLayer addAnimation:group forKey:nil]; } } else{ self.layer.backgroundColor = [UIColor colorWithHexString:UIColorWhiteOffset].CGColor; [self.checkmarkLayer setFillColor:[UIColor colorWithHexString:UIColorOrangeB0].CGColor]; [self.checkmarkLayer removeFromSuperlayer]; } } #pragma mark - CAAnimationBlock - (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag { animationCompletionBlock theBlock = [theAnimation valueForKey: kAnimationCompletionBlock]; if (theBlock) theBlock(); }
source share