Füllfarbe Animation Flackert, wenn der Aufruf von Block in Animation beendet wurde
Ich habe Probleme herauszufinden, warum die Animation vom fromValue zum toValue flackert, nachdem mein Animationsblock abgeschlossen ist. Ich weiß, dass Sie nach Abschluss einer Animation die Werte des CALayers auf den Endzustand der Animation setzen müssen, damit sie konsistent aussieht. Egal in welcher Reihenfolge ich diese Methoden nenne, ich erhalte immer das flackernde Ergebnis. Ich zeichne ein Häkchen mit einem Biezer-Pfad und fülle das Häkchen nach Abschluss der strokeEnd-Animation durch Animieren der fillColor-Eigenschaft aus. Die Funktion zum Ausfüllen von Häkchen und zum Zurücksetzen von Häkchen werden alle ausgelöst, wenn der Benutzer die Zeile der Tabellenansichtszelle auswählt, der das Häkchen zugeordnet ist. Oh ja, und ich verwende AutoLayout, wenn das einen Unterschied macht.
Ich frage mich also ein paar Dinge: 1) Sobald die Tabellenzelle angezeigt wird, rufe ich die öffentliche Funktion shoudSetCheckmarkToCheckedState auf, die den booleschen Wert self.userSelectedCheckmark auf den in der Funktion übergebenen Parameter isChecked thats setzt. Von dort rufe ich [self setNeedsLayout] auf, was layoutSubviews auslöst und die shouldDrawCheckmark ... -Funktion aufruft. Der Grund, warum ich das tue, liegt darin, dass, wenn ich die Zelle nicht zum ersten Mal zeichne, kein Rahmen festgelegt ist, sodass meine Zeichnung unordentlich aussieht. Also sollte ich jedes Mal setNeedsLayout aufrufen, wenn ich die userSelectedCheckmark-Eigenschaft ändere, oder gibt es einen besseren Weg.
2) Warum flackert das Häkchen, wenn die Animation abgeschlossen ist? Ich glaube, ich weiß warum, es liegt daran, dass nach Abschluss der Animation die Ebeneneigenschaften auf den gleichen Zustand zurückgesetzt werden, in dem sie sich befanden, als die Ebene mit der Animation begann. Also, wie kann ich das beheben? Ich würde nur einen Timer auslösen, um die Füllfarbe eine Millisekunde vor dem Ende der Animation zu ändern, aber das fühlt sich nicht richtig an.
Hier ist der Code übrigens
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();
}