【发布时间】:2014-10-20 01:55:56
【问题描述】:
在我的动画块完成后,我无法弄清楚为什么动画会从 fromValue 闪烁到 toValue。我知道在完成动画后,您必须将 CALayer 的值设置为动画的结束状态,以使其看起来一致。然而,无论我以什么顺序调用这些方法,我都会得到闪烁的结果。我正在做的是用 biezer 路径绘制一个复选标记,然后在 strokeEnd 动画完成后,我通过为 fillColor 属性设置动画来填充复选标记。填充复选标记功能和重置复选标记功能都是在用户选择与复选标记关联的tableviewcell的行时触发的。哦,我正在使用 AutoLayout,如果这有影响的话。
所以我想知道一些事情实际上是一个 1)一旦显示表格视图单元格,我调用公共函数 shoudSetCheckmarkToCheckedState 它将布尔值 self.userSelectedCheckmark 设置为在函数中传递的参数 isChecked。从那里我调用 [self setNeedsLayout],它触发 layoutSubviews 并调用 shouldDrawCheckmark... 函数。我这样做的原因是因为如果我不是第一次绘制单元格时没有设置框架,所以我的绘图看起来一团糟。所以我应该在每次更改 userSelectedCheckmark 属性时调用 setNeedsLayout 还是有更好的方法。
2) 为什么动画完成后复选标记会闪烁。我想我知道为什么,因为当动画完成时,图层属性被重置为图层开始动画时的相同状态。那么我该如何解决这个问题呢?我会在动画结束前一毫秒触发一个计时器来更改填充颜色,但这感觉不对。
这里是代码
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();
}
【问题讨论】:
-
我删除了 [self setNeedsLayout] 调用和 layoutSubviews 方法,一切正常。也许你可以上传一张出了什么问题的照片。
-
您是否将视图加载到 tableview 单元格中?
-
是的,但实际上你应该能够尽可能多地调用 [self setNeedsLayout]。我已经更新了我的答案
标签: ios core-graphics core-animation calayer uibezierpath