自己画一个ActivityIndicatorView-b

苹果的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搞定!旋转吧,小菊花!(ง •̀_•́)ง

ActiveView.gif

CAReplicatorLayer

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

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结合贝塞尔曲线画个圆就行。

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; 
}

 

posted on 2016-08-23 22:34  🌞Bob  阅读(186)  评论(0编辑  收藏  举报

导航