使用 CAShapeLayer 创建 UIActivityIndicator 动画
Posted
技术标签:
【中文标题】使用 CAShapeLayer 创建 UIActivityIndicator 动画【英文标题】:Using CAShapeLayer to create UIActivityIndicator animation 【发布时间】:2016-01-07 11:07:19 【问题描述】:我想使用CAShapeLayer
stroke 创建看起来像UIActivityIndicator
动画的动画。
我已经创建了图层:
self.ovalShapeLayer = [CAShapeLayer layer];
self.ovalShapeLayer.strokeColor = [UIColor redColor].CGColor;
self.ovalShapeLayer.fillColor = [UIColor clearColor].CGColor;
self.ovalShapeLayer.lineWidth = 15.0;
self.ovalShapeLayer.lineDashPattern = @[@1, @9];
self.ovalShapeLayer.lineDashPhase = 20.0;
self.ovalShapeLayer.lineJoin = kCALineJoinBevel;
self.ovalShapeLayer.strokeStart = 0.0;
self.ovalShapeLayer.strokeEnd = 1.0;
self.ovalShapeLayer.path = [UIBezierPath bezierPathWithOvalInRect:self.controlView.bounds].CGPath;
[self.controlView.layer addSublayer:self.ovalShapeLayer];
而且效果很好。我还可以使用
为笔画末端设置动画[CABasicAnimation animationWithKeyPath:@"strokeEnd"]
但是UIActivityIndicator
动画更复杂,因为它的破折号正在淡入/淡出,看起来像旋转。您对如何实现该动画有任何想法吗?我正在考虑使用新的CAShapeLayer
创建每个破折号,然后使用keyframe
不透明动画,但这似乎是错误的方式。
【问题讨论】:
【参考方案1】:您可以在附件中获取 1 张加载器图像,然后在 z 轴上旋转该图像。
CABasicAnimation* rotationAnimation;
rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
rotationAnimation.toValue = [NSNumber numberWithFloat: M_PI * 2.0 /* full rotation*/ * rotations * duration ];
rotationAnimation.duration = duration;
rotationAnimation.cumulative = YES;
rotationAnimation.repeatCount = repeat;
[imageView.layer addAnimation:rotationAnimation forKey:@"rotationAnimation"];
@interface CustomView ()
__weak IBOutlet UIImageView *loaderImageView;
@end
@implementation CustomView
- (id)initWithCoder:(NSCoder *)aDecoder
self = [super initWithCoder:aDecoder];
if (self)
// Initialization code
// loaderImageView = [[UIImageView alloc] initWithFrame:(CGRect)CGPointZero, 35, 35];
// loaderImageView.contentMode = UIViewContentModeScaleAspectFit;
// [self addSubview:loaderImageView];
return self;
- (void) setUp
CABasicAnimation* rotationAnimation1;
rotationAnimation1 = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
rotationAnimation1.toValue = @M_PI_2;
rotationAnimation1.duration = 1.0;
rotationAnimation1.cumulative = YES;
rotationAnimation1.repeatCount = HUGE_VALF;
[loaderImageView.layer addAnimation:rotationAnimation1 forKey:@"rotation"];
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
// Drawing code
*/
@end
【讨论】:
但是在这个方法中我需要很多 UIImageView 对象,对吗? 不,您只需要 1 张图像,在 z 轴上旋转图像会得到如附件截图所示的输出。 但我说的是 UIImageView,而不是 UIImage。我不应该查看每个破折号吗? [imageView.layer addAnimation:rotationAnimation forKey:@"rotationAnimation"];它正在使用uiimageview。在 uiimageview 中设置 1 个图像,并像在共享代码中一样旋转它的图层。它会工作 也许我没有正确理解,但我的观点是围绕它自己的轴旋转。能否提供完整代码?【参考方案2】:我花了很多时间了解 UIRefreshControl 的工作原理,包括 UIActivityIndicator。最后,我写了一个刷新控件来避免系统刷新控件中的一些问题。这是我在刷新控件中的活动指示器的代码:https://github.com/JohnWong/JWKit/blob/master/refresh-control/JWRefreshIndicatorView.m
如果你使用 lldb 来检查系统活动指示器和我的,你会发现它和 UIActivityIndicator 非常相似。 CAReplicatorLayer
是创建视图的关键。
【讨论】:
【参考方案3】:经过一些研究,我发现了很棒的课程 - CAReplicatorLayer
。
使用该类,我能够创建一个CALayer
对象并使用CATransform3D
复制它。
这是我的代码:
self.replicatorLayer = [CAReplicatorLayer layer];
self.replicatorLayer.frame = self.controlView.bounds;
[self.controlView.layer addSublayer:self.replicatorLayer];
self.dashLayer = [CALayer layer];
CGFloat dotSide = 4.0;
self.dashLayer.frame = CGRectMake(CGRectGetMidX(self.replicatorLayer.frame) - dotSide / 2, 0.0, dotSide, dotSide * 4);
self.dashLayer.backgroundColor = [UIColor redColor].CGColor;
self.dashLayer.cornerRadius = 1.5;
self.dashLayer.cornerRadius = 2.5;
[self.replicatorLayer addSublayer:self.dashLayer];
self.replicatorLayer.instanceCount = 12;
self.replicatorLayer.instanceTransform = CATransform3DMakeRotation(M_PI / 6, 0.0, 0.0, 1.0);
self.replicatorLayer.instanceDelay = 1.0 / 12;
动画看起来像这样:
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
animation.fromValue = @(1.0);
animation.toValue = @(0.0);
animation.duration = 1.0;
animation.repeatCount = CGFLOAT_MAX;
[self.dashLayer addAnimation:animation forKey:nil];
像魅力一样工作;)
【讨论】:
以上是关于使用 CAShapeLayer 创建 UIActivityIndicator 动画的主要内容,如果未能解决你的问题,请参考以下文章
iOS学习笔记: 使用CAShapeLayer创建带有空心区域的遮罩层
将 CAShapeLayer 添加到 UIButton 不起作用
iOS关于CAShapeLayer与UIBezierPath的知识内容