zoukankan      html  css  js  c++  java
  • 渐变颜色的进度条WGradientProgress-备用

    今天我们来实现一个iOS平台上的进度条(progress bar or progress view)。这种进度条比APPLE自带的更加漂亮,更加有“B格”。它拥有渐变的颜色,而且这种颜色是动态移动的,这里称之为WGradientProgress。

    先来看看我们的目标长什么样子:

       

    WGradientProgress的使用方法很简单,主要有展示接口以及隐藏接口,目前显示的位置有两种选择:

    • WProgressPosDown        //progress is on the down border of parent view,显示在parent view的底部(主流做法,默认)

    • WProgressPosUp           //progress is on the up border of parent view,也就是显示在parent view的顶部

    主要的接口有以下几个:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    + (WGradientProgress *)sharedInstance;
     
    /**
     *  the main interface to show WGradientProgress obj, position is WProgressPosDown by default.
     *
     *  @param parentView which view to be attach
     */
    - (void)showOnParent:(UIView *)parentView;
     
    /**
     *  the main interface to show WGradientProgress obj
     *
     *  @param parentView which view to be attach
     *  @param pos        up or down
     */
    - (void)showOnParent:(UIView *)parentView position:(WProgressPos)pos;
     
    /**
     *  the main interface to hide WGradientProgress obj
     */
    - (void)hide;

      


    分析

    这里我们看一下,实现出这样的效果需要解决哪些技术难点:

    • 如何实现一个静态的具有渐变颜色的色带
    • 如何实现色带颜色循环移动
    • 如何关联进度值与色带的宽度

    (1)如何实现一个静态的具有渐变颜色的色带

    这里需要使用CALayer的子类CAGradientLayer。CAGradientLayer用于实现颜色渐变,关于CAGradietnLayer的介绍请看这里。我们使用到的属性有startPoint、endPoint、colors。

    我们可以这样子做出一个静态的渐变色带,你也可以修改colors数组来实现不同颜色的色带:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    if (self.gradLayer == nil) {
        self.gradLayer = [CAGradientLayer layer];
        self.gradLayer.frame = self.bounds;//尺寸要与view的layer一致
    }
    self.gradLayer.startPoint = CGPointMake(0, 0.5);
    self.gradLayer.endPoint = CGPointMake(1, 0.5);
     
    //create colors, important section
    NSMutableArray *colors = [NSMutableArray array];
    for (NSInteger deg = 0; deg <= 360; deg += 5) {
         
        UIColor *color;
        color = [UIColor colorWithHue:1.0 * deg / 360.0
                           saturation:1.0
                           brightness:1.0
                                alpha:1.0];
        [colors addObject:(id)[color CGColor]];
    }
    [self.gradLayer setColors:[NSArray arrayWithArray:colors]];

     (2)如何实现色带颜色循环移动

    色带颜色循环向前移动,本质上是渐变图层gradientLayer的colors数组循环变化。如果理解了这点,那就很容易往下做了。我的做法是使用定时器NSTimer,让定时器的执行方法去循环地改变color数组。另外,既然要做到循环,那么应该循环地取colors数组的最后一个颜色值插到数组开始处。定时器的执行代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    /**
     *  here I use timer to circularly move colors
     */
    - (void)setupTimer
    {
        CGFloat interval = 0.03;
        if (self.timer == nil) {
             self.timer = [NSTimer timerWithTimeInterval:interval target:self
                                                selector:@selector(timerFunc)
                                                userInfo:nil repeats:YES];
        }
        [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
    }
     
    /**
     *  rearrange color array
     */
    - (void)timerFunc
    {
        CAGradientLayer *gradLayer = self.gradLayer;
        NSMutableArray *copyArray = [NSMutableArray arrayWithArray:[gradLayer colors]];
        UIColor *lastColor = [copyArray lastObject];
        [copyArray removeLastObject];
        if (lastColor) {
            [copyArray insertObject:lastColor atIndex:0];
        }
        [self.gradLayer setColors:copyArray];
    }

      


    *强势插入:

      NSTimer的启动、暂停、永远停止这三个操作要分清,尤其是暂停与停止:

    • 启动:  
    1
    2
    3
    4
    5
    6
    - (void)startTimer
    {
        //start timer
        [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
        [self.timer setFireDate:[NSDate date]];
    }
    • 暂停:
    1
    2
    3
    4
    5
    6
    7
    8
    /**
     *  here we just pause timer, rather than stopping forever.
     *  NOTE: [timer invalidate] is not fit here.
     */
    - (void)pauseTimer
    {
        [self.timer setFireDate:[NSDate distantFuture]];
    }
    •  停止(无法再启动):
    1
    [self.timer invalidate]

    (3)如何关联进度值与色带的宽度

    这个问题看起来很简单,但实际上隐藏着一个很好用的技术:mask。mask也称为蒙版,当我们给一个layer设置了mask layer后,layer就只显示出mask layer所覆盖到的区域,其他区域不显示。用伪代码可以描述为:

    1
    2
    3
    CALayer *layer = new
    layer.mask = _maskLayer;
    layer.visualSection = _maskLayer.bounds;

    因此,我们可以将在一开始时就上文的渐变图层gradientLayer大小设置为与view同尺寸,然后通过mask layer设置可见区域。这样,进度条进度值设置问题就转化为mask layer的宽度问题了。

    首先,我们添加一个mask layer到gradient layer上:

    1
    2
    3
    4
    5
    6
    7
    self.mask = [CALayer layer];
    [self.mask setFrame:CGRectMake(self.gradLayer.frame.origin.x, self.gradLayer.frame.origin.y,
                                   self.progress * self.width, self.height)];
    self.mask.borderColor = [[UIColor blueColor] CGColor];
    self.mask.borderWidth = 2;
    [self.gradLayer setMask:self.mask];
    [self.layer addSublayer:self.gradLayer];

    然后相应进度值的改变如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    - (void)setProgress:(CGFloat)progress
    {
        if (progress < 0) {
            progress = 0;
        }
        if (progress > 1) {
            progress = 1;
        }
        _progress = progress;
        CGFloat maskWidth = progress * self.width;
        self.mask.frame = CGRectMake(0, 0, maskWidth, self.height);
    }

     以上就是WGradientProgress的主要技术要点,更具体的细节以及使用方法请下载我github上的代码查看,下载时别忘记随手点个Star,给我更多支持与鼓励!

    源代码下载:点我。https://github.com/weng1250/WGradientProgressDemo.git

  • 相关阅读:
    Word如何去水印
    计算机二级公共基础知识 #02
    计算机二级公共基础知识 #01
    Linux常用快捷键
    计算机二级C语言概述 #00
    信管专业的同学都进来看一看叭~~~~~
    Python--Hanoi塔问题
    MATLAB——实验一:查看图像的RGB值
    Python课 #06号作业
    Python课 #05号作业
  • 原文地址:https://www.cnblogs.com/isItOk/p/5304286.html
Copyright © 2011-2022 走看看