渐变颜色的进度条WGradientProgress-备用

本文介绍了一种iOS平台上美观的动态渐变进度条组件WGradientProgress,它具有颜色渐变且能动态移动的特点。文章详细讲解了其实现原理和技术难点,包括使用CAGradientLayer创建渐变色带、通过NSTimer实现颜色循环移动及利用mask层关联进度值与色带宽度。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值