【原】Github系列之三:开源iOS下 渐变颜色的进度条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,给我更多支持与鼓励! 本文转自编程小翁博客园博客,原文链接:http://www.cnblogs.com/wengzilin/p/4665038.html,如需转载请自行联系原作者