苹果的UI控件中有一个UIActivityIndicatorView,俗称菊花。→_→
现在我们仿照它来制作一个其它样式的指示器,如下:

ActivityView.png

自定义指示器

首先画一个白色的扇形。
创建一个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);
}

之后创建一个MyActiveView类继承自UIView,把上面创建的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);        // 调用layer的drawInContext:进行绘图        
       [layer setNeedsDisplay];        // 设置2倍比率,防止边缘出现锯齿        
       layer.contentsScale = 2;        // 透明        
       layer.opacity = 0;        // 设置锚点        
       layer.anchorPoint = CGPointMake(0.5, 0);        // 设置第一个扇形layer的位置        
       layer.position = CGPointMake(self.bounds.size.width/2, 0);        
       [repLayer addSublayer:layer];        // 设置透明度渐变的动画        
       opacityAnim = [CABasicAnimation animationWithKeyPath:@"opacity"];        // 透明度从1变为0        
       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;        // 复制8个        
       repLayer.instanceCount = count;        // 绕z轴每隔angle角度复制一个        
       repLayer.instanceTransform = CATransform3DMakeRotation(angle, 0, 0, 1);        // 复制子层动画延迟时长        
       repLayer.instanceDelay = duration / count;        // 此视图绕z轴旋转22度        
       CATransform3D transform = CATransform3DRotate(self.layer.transform, 22*M_PI/180, 0, 0, 1);        self.layer.transform = transform;        // 监听App进入前后台        
       [[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];
}

接下来就可以创建使用了。记得把视图控制器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搞定!旋转吧,小菊花!(ง •̀_•́)ง

aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkJDQzA1MTVGNkE2MjExRTRBRjEzODVCM0Q0NEVFMjFBIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkJDQzA1MTYwNkE2MjExRTRBRjEzODVCM0Q0NEVFMjFBIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QkNDMDUxNUQ2QTYyMTFFNEFGMTM4NUIzRDQ0RUUyMUEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QkNDMDUxNUU2QTYyMTFFNEFGMTM4NUIzRDQ0RUUyMUEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6p+a6fAAAAD0lEQVR42mJ89/Y1QIABAAWXAsgVS/hWAAAAAElFTkSuQmCC" alt="" data-ratio="1.7857142857142858" data-src="http://mmbiz.qpic.cn/mmbiz_gif/g4uoJOMA38IaGo10L2N0W1ZsUiaJ9CSGCwNPRIJnL18Z7wRibcVIibcAu7udm5809XibsONhIODQDSOK2EsjXExVCQ/0?wx_fmt=gif" data-type="gif" data-w="224" />

ActiveView.gif

CAReplicatorLayer

使用CAReplicatorLayer可以创建出很多类似的重复动画效果,比如:

aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkJDQzA1MTVGNkE2MjExRTRBRjEzODVCM0Q0NEVFMjFBIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkJDQzA1MTYwNkE2MjExRTRBRjEzODVCM0Q0NEVFMjFBIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QkNDMDUxNUQ2QTYyMTFFNEFGMTM4NUIzRDQ0RUUyMUEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QkNDMDUxNUU2QTYyMTFFNEFGMTM4NUIzRDQ0RUUyMUEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6p+a6fAAAAD0lEQVR42mJ89/Y1QIABAAWXAsgVS/hWAAAAAElFTkSuQmCC" alt="" data-ratio="0.5811965811965812" data-src="http://mmbiz.qpic.cn/mmbiz_gif/g4uoJOMA38IaGo10L2N0W1ZsUiaJ9CSGCPGqaLVOibMQSBibofY6PQUIGN0ibSVLG2se7n0CVCdwqbiawV3ae0Aw0XA/0?wx_fmt=gif" data-type="gif" data-w="234" />

ActiveViews.gif

这些都是常见的指示器效果,它们的代码如下:

条形指示器

创建一个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等分之后创建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;        // 每次重复效果跟上次相反        
       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];
环形指示器

创建一个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;        // 设置子层总数        
       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来创建,只需要用CAShapeLayer结合贝塞尔曲线画个圆就行。

aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkJDQzA1MTVGNkE2MjExRTRBRjEzODVCM0Q0NEVFMjFBIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkJDQzA1MTYwNkE2MjExRTRBRjEzODVCM0Q0NEVFMjFBIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QkNDMDUxNUQ2QTYyMTFFNEFGMTM4NUIzRDQ0RUUyMUEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QkNDMDUxNUU2QTYyMTFFNEFGMTM4NUIzRDQ0RUUyMUEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6p+a6fAAAAD0lEQVR42mJ89/Y1QIABAAWXAsgVS/hWAAAAAElFTkSuQmCC" alt="" data-ratio="0.967741935483871" data-src="http://mmbiz.qpic.cn/mmbiz_gif/g4uoJOMA38IaGo10L2N0W1ZsUiaJ9CSGCpZP86JSGclRqDJQ2uTXsoHKiaicXiaWIJ2ic1Kicicuqy7loDl4yibjZANKXQ/0?wx_fmt=gif" data-type="gif" data-w="124" />

Round.gif

代码如下:

- (instancetype)initWithFrame:(CGRect)frame {    
   if (self = [super initWithFrame:frame]) {        // 设置直径为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;
}

自己画一个ActivityIndicatorView-b的更多相关文章

  1. Effective前端3:用CSS画一个三角形

    p { text-indent: 2em } .triangle-container p { text-indent: 0 } img { margin: 15px 0 } 三角形的场景很常见,打开一 ...

  2. canvas游戏小试:画一个按方向键移动的圆点

    canvas游戏小试:画一个按方向键移动的圆点   自己对canvas,但又有一颗做游戏的心TT.然后记录一下对canvas的学习吧,用一个按方向键控制的小圆点来做练习.(编程时用了一些es6的语法) ...

  3. PostScript的简单例子-用粗线画一个圆

    一 近期需要用到PostScript,查询资料学习PS的语法 简单的画一个圆的例子 %!PS-Adobe-3.0 /inch{72 mul} def 4.25 inch 5.5 inch 1.5 in ...

  4. Android画一个随意拖动的圆形

    import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactor ...

  5. 用PS画一个齿轮

    以前只会画圆画方,这没技术含量.今天学了一个稍难一点的,画一个齿轮.图形有圆也有方.以下描述如何画出来的. 一.打开PS准备一画布,画一矩形并且填充颜色. 二.编辑->自由变换(CTRL+T), ...

  6. 深夜,用canvas画一个时钟

    深夜,用canvas画一个时钟 查看demo 这几天准备阿里巴巴的笔试,可以说已经是心力交瘁,自从阿里和蘑菇街的内推被刷掉之后,开始越来越怀疑起自己的能力来,虽然这点打击应该是微不足道的.毕竟校招在刚 ...

  7. Directx11学习笔记【十二】 画一个旋转的彩色立方体

    上一次我们学习了如何画一个2D三角形,现在让我们进一步学习如何画一个旋转的彩色立方体吧. 具体流程同画三角形类似,因此不再给出完整代码了,不同的部分会再说明. 由于我们要画彩色的立方体,所以顶点结构体 ...

  8. Directx11学习笔记【十一】 画一个简单的三角形--effect框架的使用

    这里不再介绍effect框架的具体使用,有关effect框架使用可参考http://www.cnblogs.com/zhangbaochong/p/5475961.html 实现的功能依然是画一个简单 ...

  9. css3简单几步画一个乾坤图

    原文:[原创]css3简单几步画一个乾坤图 效果如上,鼠标移上去会有动画. 代码如下非常简单: <html> <head> <style> .outer{heigh ...

随机推荐

  1. Java基础知识强化之网络编程笔记20:Android网络通信之 Android常用OAuth登录和分享

    1.  申请百度开发者账号及百度OAuth简介. (1)申请开发者账号: http://developer.baidu.com/ (2)创建项目: http://developer.baidu.com ...

  2. apply方法别有他用!

    首先是apply()一个很强大的功能——能将一个数组默认转化为参数列表!!! 应用: 1.求出一个数组中的最大值 var arr= [1, 3, 3, 6]; var max =Math.max.ap ...

  3. swift 如何使用OC中宏的功能

    swift中没有宏的概念,那么我们在swift使用宏的功能来提高效率呢? 一.使用关键字 let 来声明一个常量 存储相应的值,以下代码声明了常量  myColor 来存储一种指定的颜色 let my ...

  4. 关于Git的工作区域和对应的文件状态.

    Git是一个免费的.分布式的版本控制工具,或是一个强调了速度快的源代码管理工具.每一个Git的工作目录都是一个完全独立的代码库,并拥有完整的历史记录和版本追踪能力,不依赖于网络和中心服务器. Git ...

  5. SpringMVC文件上传 Excle文件 Poi解析 验证 去重 并批量导入 MYSQL数据库

    SpringMVC文件上传 Excle文件 Poi解析并批量导入 MYSQL数据库  /** * 业务需求说明: * 1 批量导入成员 并且 自主创建账号 * 2 校验数据格式 且 重复导入提示 已被 ...

  6. 理解Spark的RDD

    RDD是个抽象类,定义了诸如map().reduce()等方法,但实际上继承RDD的派生类一般只要实现两个方法: def getPartitions: Array[Partition] def com ...

  7. RabbitMQ 原文译1.1--HelloWord

    本系列文章均来自官网原文,属于个人翻译,如有雷同,权当个人归档,忽喷. RabitMQ 是一个消息中间件,其实就是从消息生产者那里接受消息,然后发送给消息消费者.在这个传输过程中,可以定义一些缓存,持 ...

  8. 《Pro Git》学习笔记

    1.Git远程模型示意图 Remote:远程仓库 Repository:本地仓库 Index:暂存区 workspace:当前工作区 2.取得Git仓库 2.1 初始化新仓库     git init ...

  9. 在shell的if条件里,判断 a>0 且 (b>0 或 c>0) ,如何编写?

    if [ $b -gt 0 -o $c -gt 0 -a $a -gt 0 ]; then.fi对shell中的关系运算符说明如下:-gt 表示greater than,大于-lt 表示less th ...

  10. 2013年全国各大著名的IT公司薪资待遇大揭密

    以下为转载,特此说明!--西电好网 ============================================ 1: 本人西电通院2013届毕业硕士,根据今年找工作的情况以及身边同学的汇 ...