zoukankan      html  css  js  c++  java
  • 自己画一个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; 
    }
  • 相关阅读:
    wsl 如何去掉 windows 的环境变量
    wget出现Unable to establish SSL connection
    openssh 升级
    element/JS文件上传和下载excel问题
    mysql操作过程中常见问题汇总
    [VB.NET Tips]线程传递参数四种方法
    主路由拨号_openwrt做旁路由_ipv4端口映射的设置
    Openwrt_Linux_crontab任务_顺序执行脚本
    Armbian_笔记
    Debian10_Centos8_fail2ban
  • 原文地址:https://www.cnblogs.com/isItOk/p/5801088.html
Copyright © 2011-2022 走看看