A animação de preenchimento colorido pisca quando o bloco de chamada na animação parou
Estou tendo problemas para descobrir por que a animação está piscando do fromValue para o toValue após a conclusão do meu bloco de animação. Sei que depois de concluir uma animação, você deve definir os valores do CALayer para o estado final da animação para manter a aparência consistente. No entanto, não importa em que ordem eu chamo esses métodos, continuo obtendo o resultado oscilante. O que estou fazendo é desenhar uma marca de seleção com um caminho biezer e, depois que a animação strokeEnd for concluída, preencha a marca de seleção animando a propriedade fillColor. A função de preenchimento da marca de seleção e a função de redefinição da marca de seleção são acionadas quando o usuário seleciona a linha da célula da tableview à qual a marca de seleção está associada. Ah, estou usando o AutoLayout, se isso faz diferença.
Então, eu estou pensando em algumas coisas, na verdade 1) Uma vez que a célula de exibição de tabela está sendo exibida, eu chamo a função pública shoudSetCheckmarkToCheckedState, que define o booleano self.userSelectedCheckmark para o parâmetro isChecked, que é passado na função. A partir daí, chamo [self setNeedsLayout], que aciona layoutSubviews e chama a função shouldDrawCheckmark .... A razão pela qual faço isso é porque, se não fizer a primeira vez que a célula é desenhada, não há um quadro definido, então meu desenho parece uma bagunça. Então, eu deveria estar chamando setNeedsLayout toda vez que altero a propriedade userSelectedCheckmark ou existe uma maneira melhor.
2) Por que a marca de seleção pisca quando a animação é concluída. Eu acho que sei porque, é porque quando a animação termina as propriedades das camadas são redefinidas para o mesmo estado em que estavam quando a camada começou a animar. Então, como posso corrigir isso? Eu acionaria um timer para alterar a cor de preenchimento um milissegundo antes que a animação terminasse, mas isso não parece certo.
aqui está o código btw
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();
}