今天我们来实现一个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

渐变颜色的进度条WGradientProgress-备用的更多相关文章

  1. 【原】Github系列之三:开源iOS下 渐变颜色的进度条WGradientProgress

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

  2. 纯css使用线性渐变实现滚动进度条(来自于微信前端早读课)

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. 【iOS实现一个颜色渐变的弧形进度条】

    在Github上看到一些进度条的功能,都是通过Core Graph来实现.无所谓正确与否,但是开发效率明显就差很多了,而且运行效率还是值得考究的.其实使用苹果提供的Core Animation能够非常 ...

  4. 超炫的HTML5粒子效果进度条 VS 如何规范而优雅地code

    最近瞎逛的时候发现了一个超炫的粒子进度效果,有多炫呢?请擦亮眼镜!   // _this.ch){ _this.particles.splice(i, 1); } }; this.Particle.p ...

  5. BootStrap入门教程 (三) :可重用组件(按钮,导航,标签,徽章,排版,缩略图,提醒,进度条,杂项)

    上讲回顾:Bootstrap的基础CSS(Base CSS)提供了优雅,一致的多种基础Html页面要素,包括排版,表格,表单,按钮等,能够满足前端工程师的基本要素需求. Bootstrap作为完整的前 ...

  6. Bootstrap进度条

    前面的话 在网页中,进度条的效果并不少见,比如一个评分系统,比如加载状态等,通过简单.灵活的进度条,可以为当前工作流程或动作提供实时反馈.本文将详细介绍Bootstrap进度条 基本样式 Bootst ...

  7. 不可思议的纯 CSS 滚动进度条效果

    结论先行,如何使用 CSS 实现下述滚动条效果? 就是顶部黄色的滚动进度条,随着页面的滚动进度而变化长短. 在继续阅读下文之前,你可以先缓一缓.尝试思考一下上面的效果或者动手尝试一下,不借助 JS , ...

  8. Android多种样式的进度条

    原创 2016年04月26日 16:46:35 标签: android / clip / 进度条 / 8473 编辑 删除 ---- The mark of the immature man is t ...

  9. Bootstrap各种进度条的实例讲解

    本章将讲解 Bootstrap 进度条.在本教程中,您将看到如何使用bootstrap教程.重定向或动作状态的进度条. Bootstrap 进度条使用 CSS3 过渡和动画来获得该效果.Interne ...

随机推荐

  1. 【转】ArrayList和LinkedList的几种循环遍历方式及性能对比分析

    原文网址:http://www.trinea.cn/android/arraylist-linkedlist-loop-performance/ 主要介绍ArrayList和LinkedList这两种 ...

  2. delphi7调用webservice Java 传入参数为空

    在delphi7中,new-webservices-wsdl importer中输入wsdl地址,会自动生成wsdl单元代码.在调用时,传入参数到服务器端时为空了. 网上说缺少 InvRegistry ...

  3. Codeforces Round #236 (Div. 2)E. Strictly Positive Matrix(402E)

    E. Strictly Positive Matrix   You have matrix a of size n × n. Let's number the rows of the matrix f ...

  4. POJ 3009 深度优先搜索

    问题:打冰球.冰球可以往上下左右4个方向走,只有当冰球撞到墙时才会停下来,而墙会消失.当冰球紧贴墙时,不能将冰球往那个方向打.冰球出界就当输,超过10次还没将冰球打到目标位置也当输.求用最小次数将冰球 ...

  5. Java ConcurrentHashmap 解析

    总体描述: concurrentHashmap是为了高并发而实现,内部采用分离锁的设计,有效地避开了热点访问.而对于每个分段,ConcurrentHashmap采用final和内存可见修饰符Volat ...

  6. redis报错

    网站登录异常,redis数据不能写!解决方法汇总! redis---flushdb  ###提示如下错误    ###flushall              清空说有数据,所有库 (error) ...

  7. servlet过滤器配置白名单、黑名单

    1.web.xml配置 <filter> <description>过滤是否登陆</description> <filter-name>encoding ...

  8. mnist数据集转换bmp图片

    Mat格式mnist数据集下载地址:http://www.cs.nyu.edu/~roweis/data.html Matlab转换代码: load('mnist_all.mat'); type = ...

  9. Swift2.0下UICollectionViews拖拽效果的实现

    文/过客又见过客(简书作者)原文链接:http://www.jianshu.com/p/569c65b12c8b著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”. 原文UICollecti ...

  10. Node.js 实现简单小说爬虫

    最近因为剧荒,老大追了爱奇艺的一部网剧,由丁墨的同名小说<美人为馅>改编,目前已经放出两季,虽然整部剧槽点满满,但是老大看得不亦乐乎,并且在看完第二季之后跟我要小说资源,直接要奔原著去看结 ...