蘋果的UI控件中有一個UIActivityIndicatorView,俗稱菊花×认→_→
現(xiàn)在我們仿照它來制作一個其它樣式的指示器,如下:
ActivityView.png
自定義指示器
首先畫一個白色的扇形关霸。
創(chuàng)建一個MyLayer類繼承自CALayer传黄,重寫它的繪圖方法- (void)drawInContext:(CGContextRef)ctx
:
- (void)drawInContext:(CGContextRef)ctx
{
CGContextSetRGBFillColor(ctx, 1, 1, 1, 1);
CGContextSetRGBStrokeColor(ctx, 1, 1, 1, 1);
CGContextMoveToPoint(ctx, CGRectGetMaxX(self.bounds)/2, CGRectGetMaxY(self.bounds));
// 順時針從-70度畫到-110度 (0度是3點鐘方向)
CGContextAddArc(ctx, CGRectGetMaxX(self.bounds)/2, CGRectGetMaxY(self.bounds), 20, -70 * M_PI / 180, -110 * M_PI / 180, 1);
CGContextClosePath(ctx);
CGContextDrawPath(ctx, kCGPathFillStroke);
}
之后創(chuàng)建一個MyActiveView類繼承自UIView,把上面創(chuàng)建的layer添加到MyActiveView上队寇。
@implementation MyActiveView
{
MyLayer *layer;
CABasicAnimation *opacityAnim;
}
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
self.backgroundColor = [UIColor clearColor];
CAReplicatorLayer *repLayer = [CAReplicatorLayer layer];
repLayer.frame = self.bounds;
[self.layer addSublayer:repLayer];
// 畫一個扇形的layer
layer = [MyLayer layer];
layer.frame = CGRectMake(0, 0, 22, 22);
// 調(diào)用layer的drawInContext:進(jìn)行繪圖
[layer setNeedsDisplay];
// 設(shè)置2倍比率膘掰,防止邊緣出現(xiàn)鋸齒
layer.contentsScale = 2;
// 透明
layer.opacity = 0;
// 設(shè)置錨點
layer.anchorPoint = CGPointMake(0.5, 0);
// 設(shè)置第一個扇形layer的位置
layer.position = CGPointMake(self.bounds.size.width/2, 0);
[repLayer addSublayer:layer];
// 設(shè)置透明度漸變的動畫
opacityAnim = [CABasicAnimation animationWithKeyPath:@"opacity"];
// 透明度從1變?yōu)?
opacityAnim.fromValue = [NSNumber numberWithFloat:1.0];
opacityAnim.toValue = [NSNumber numberWithFloat:0];
opacityAnim.removedOnCompletion = YES;
opacityAnim.repeatCount = MAXFLOAT;
CGFloat duration = 0.7;
opacityAnim.duration = duration;
[layer addAnimation:opacityAnim forKey:nil];
int count = 8;
CGFloat angle = M_PI * 2 / count;
// 復(fù)制8個
repLayer.instanceCount = count;
// 繞z軸每隔angle角度復(fù)制一個
repLayer.instanceTransform = CATransform3DMakeRotation(angle, 0, 0, 1);
// 復(fù)制子層動畫延遲時長
repLayer.instanceDelay = duration / count;
// 此視圖繞z軸旋轉(zhuǎn)22度
CATransform3D transform = CATransform3DRotate(self.layer.transform, 22*M_PI/180, 0, 0, 1);
self.layer.transform = transform;
// 監(jiān)聽App進(jìn)入前后臺
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(stop) name:UIApplicationWillResignActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(start) name:UIApplicationDidBecomeActiveNotification object:nil];
}
return self;
}
// 停止動畫
- (void)stop
{
[layer removeAllAnimations];
}
// 開始動畫
- (void)start
{
[layer addAnimation:opacityAnim forKey:nil];
}
接下來就可以創(chuàng)建使用了。記得把視圖控制器view的白色改為其它顏色佳遣,否則你是看不到這個白色指示器的识埋。
MyActiveView *activityView = [[MyActiveView alloc] initWithFrame:CGRectMake(self.view.bounds.size.width/2-25, self.view.bounds.size.height-200, 50, 50)];
[self.view addSubview:activityView];
OK搞定!旋轉(zhuǎn)吧苍日,小菊花惭聂!(? ??_??)?
ActiveView.gif
CAReplicatorLayer
使用CAReplicatorLayer可以創(chuàng)建出很多類似的重復(fù)動畫效果,比如:
ActiveViews.gif
這些都是常見的指示器效果相恃,它們的代碼如下:
條形指示器
創(chuàng)建一個ActiveView1類辜纲,繼承自UIView。
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
CAReplicatorLayer *repLayer = [CAReplicatorLayer layer];
repLayer.frame = self.bounds;
[self.layer addSublayer:repLayer];
CALayer *layer = [CALayer layer];
// 寬度5等分之后創(chuàng)建3個repLayer
CGFloat width = frame.size.width/5;
CGFloat height = frame.size.height;
layer.bounds = CGRectMake(0, 0, width, height);
// 第一個layer的位置
layer.position = CGPointMake(width/2, height/2);
layer.backgroundColor = [UIColor greenColor].CGColor;
[repLayer addSublayer:layer];
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.scale.y"];
animation.fromValue = @1;
animation.toValue = @0.3;
animation.duration = 0.4;
// 每次重復(fù)效果跟上次相反
animation.autoreverses = YES;
animation.repeatCount = CGFLOAT_MAX;
[layer addAnimation:animation forKey:nil];
repLayer.instanceCount = 3;
repLayer.instanceDelay = 0.2;
// x軸上每隔self.frame.size.width/5*2距離拦耐,放置一個repLayer
repLayer.instanceTransform = CATransform3DMakeTranslation(frame.size.width/5*2, 0, 0);
}
return self;
}
在控制器中添加它即可:
ActiveView1 *view1 = [[ActiveView1 alloc] initWithFrame:CGRectMake(20, 200, 70, 50)];
[self.view addSubview:view1];
環(huán)形指示器
創(chuàng)建一個ActiveView2類耕腾,繼承自UIView。
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
CAReplicatorLayer *repLayer = [CAReplicatorLayer layer];
repLayer.frame = self.bounds;
[self.layer addSublayer:repLayer];
CALayer *layer = [CALayer layer];
layer.bounds = CGRectMake(0, 0, 10, 10);
layer.cornerRadius = 5;
layer.masksToBounds = YES;
layer.transform = CATransform3DMakeScale(0, 0, 0);
// 第一個layer的位置
layer.position = CGPointMake(frame.size.width/2, 5);
layer.backgroundColor = [UIColor greenColor].CGColor;
[repLayer addSublayer:layer];
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
animation.fromValue = @1;
animation.toValue = @0.2;
CGFloat duration = 1.2;
animation.duration = duration;
animation.repeatCount = CGFLOAT_MAX;
[layer addAnimation:animation forKey:nil];
int count = 12;
// 360度分成12份
CGFloat angle = M_PI * 2 / count;
// 設(shè)置子層總數(shù)
repLayer.instanceCount = count;
repLayer.instanceTransform = CATransform3DMakeRotation(angle, 0, 0, 1);
repLayer.instanceDelay = duration / count;
}
return self;
}
在控制器中添加它:
ActiveView2 *view2 = [[ActiveView2 alloc] initWithFrame:CGRectMake(150, 200, 70, 70)];
[self.view addSubview:view2];
另外一種指示器
除了上面三種指示器杀糯,還有一種指示器比較常見扫俺,不過它的代碼跟上面的不太一樣,它不需要使用CAReplicatorLayer來創(chuàng)建固翰,只需要用CAShapeLayer結(jié)合貝塞爾曲線畫個圓就行狼纬。
Round.gif
代碼如下:
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
// 設(shè)置直徑為self寬/高的最小值
CGFloat diameter = MIN(frame.size.width, frame.size.height);
CAShapeLayer *sLayer = [CAShapeLayer layer];
sLayer.anchorPoint = CGPointMake(0.5, 0.5);
sLayer.frame = CGRectMake(0, 0, diameter, diameter);
sLayer.strokeColor = [UIColor greenColor].CGColor;
sLayer.fillColor = [UIColor clearColor].CGColor;
sLayer.lineWidth = 2;
CGFloat raduis = diameter/2;
UIBezierPath *roundPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(raduis, raduis)
radius:raduis
startAngle:0
endAngle:(2*M_PI-M_PI_4)
clockwise:YES];
sLayer.path = roundPath.CGPath;
[self.layer addSublayer:sLayer];
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
animation.fromValue = @0;
animation.toValue = @(2*M_PI);
animation.duration = 1.f;
animation.repeatCount = CGFLOAT_MAX;
[sLayer addAnimation:animation forKey:nil];
}
return self;
}
先介紹以上幾種指示器,如果有比較好看的新的指示器骂际,我會繼續(xù)更新疗琉。