之前有人在找漸變進度條的效果,閑來無事就順手寫了一個,然后畫了視圖層級,方便講解。
環境信息:
Mac OS X 10.10.3
Xcode 6.3.1
iOS 8.3
效果圖:
源碼下載地址:
正文
一、視圖層級
首先需要搞定的就是視圖層級關系。可以看到,
1. 背景是有透明度的藍色(blueView)
2. 需要一個從綠->黃->紅的漸變色,那個這里我采用的是Layer(colorLayer)
3. blueView和colorLayer他們的表現狀態都是環形的,所以還需要環形的遮罩
4. 藍色的環並沒有變,而漸變色的環卻在時刻變化,所以需要兩個遮罩,一個給藍色(blueMaskLayer),一個給漸變色(colorMaskLayer)
從上面的分析可以看出,現在需要幾個變量以及他們的關系如下:
[viewController.view addSubView:blueView];
[blueView.layer addSubLayer:colorLayer];
colorLayer.mask = colorMaskLayer;
blueView.layer.mask = blueMaskLayer;
視圖層級圖如下:

視圖層級圖
二、根據視圖層級來實現
搞清楚了層級,接着就應該逐個實現了。
1. 有透明度的藍色視圖blueView
ViewController.m
BlueView *blueView = [[BlueView alloc] initWithFrame:CGRectMake(0, 0, 300, 300)]; blueView.center = self.view.center; blueView.backgroundColor = [UIColor blueColor]; // 我這里沒有給透明度 [self.view addSubView:blueView];
2. 漸變圖層colorLayer
因為系統沒有提供根據路徑漸變的實現方法,所以只能采用曲線救國的方式來畫。那么我所使用的方法是:在左邊畫一個從下往上為綠->黃的漸變Layer(leftLayer),然后右邊畫一個從下往上為紅->黃的漸變Layer(rightLayer)。
效果圖如下:

漸變色
但是這種方式效果不是很好,因為黃綠色和橘紅色的分界太明顯,所以最好設置一個漸變的范圍。
效果圖如下:

設置漸變范圍的漸變色
實現代碼:
BlueView.m
- (void)setupColorLayer { self.colorLayer = [CAShapeLayer layer]; self.colorLayer.frame = self.bounds; [self.layer addSublayer:self.colorLayer]; CAGradientLayer *leftLayer = [CAGradientLayer layer]; leftLayer.frame = CGRectMake(0, 0, self.bounds.size.width / 2, self.bounds.size.height); // 分段設置漸變色 leftLayer.locations = @[@0.3, @0.9, @1]; leftLayer.colors = @[(id)[UIColor yellowColor].CGColor, (id)[UIColor greenColor].CGColor]; [self.colorLayer addSublayer:leftLayer]; CAGradientLayer *rightLayer = [CAGradientLayer layer]; rightLayer.frame = CGRectMake(self.bounds.size.width / 2, 0, self.bounds.size.width / 2, self.bounds.size.height); rightLayer.locations = @[@0.3, @0.9, @1]; rightLayer.colors = @[(id)[UIColor yellowColor].CGColor, (id)[UIColor redColor].CGColor]; [self.colorLayer addSublayer:rightLayer]; }
3. 漸變圖層的環形遮罩colorMaskLayer
因為漸變圖層環形遮罩和藍色視圖的環形遮罩樣式都是一樣的,所以可以將環形遮罩的創建代碼封裝出來:
BlueView.m
- (CAShapeLayer *)generateMaskLayer { CAShapeLayer *layer = [CAShapeLayer layer]; layer.frame = self.bounds; // 創建一個圓心為父視圖中點的圓,半徑為父視圖寬的2/5,起始角度是從-240°到60° UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2) radius:self.bounds.size.width / 2.5 startAngle:-3 / 4 * M_PI endAngle:1 / 3 * M_PI clockwise:YES]; layer.lineWidth = 20; layer.path = path.CGPath; layer.fillColor = [UIColor clearColor].CGColor; // 填充色為透明(不設置為黑色) layer.strokeColor = [UIColor blackColor].CGColor; // 隨便設置一個邊框顏色 layer.lineCap = kCALineCapRound; // 設置線為圓角 return layer; }
設置漸變色環形遮罩層
BlueView.m
- (void)setupColorMaskLayer { CAShapeLayer *layer = [self generateMaskLayer]; layer.lineWidth = 20.5; // 漸變遮罩線寬較大,防止藍色遮罩有邊露出來 self.colorLayer.mask = layer; self.colorMaskLayer = [CAShapeLayer layer]; self.colorMaskLayer = layer; }
4. blueView的環形遮罩blueMaskLayer
BlueView.m
- (void)setupBlueMaskLayer { CAShapeLayer *layer = [self generateMaskLayer]; self.layer.mask = layer; self.blueMaskLayer = layer; }
5. 設置百分比
設置漸變色所占的百分比,其實就是改變colorMaskLayer的范圍,系統提供了一個方法可以直接根據百分比來修改。
self.colorMaskLayer.strokeEnd = 0.5;
到此,整個效果就已經完成了,接下來說一下回彈動畫。
三、設置回彈動畫
我所使用的是pop庫中的POPSpringAnimation,這個效果比較Q彈,加在進度條上剛好。要加動畫,只需要把上面的修改strokeEnd的代碼換成一下方法就可以了:
- (void)animationWithStrokeEnd:(CGFloat)strokeEnd { POPSpringAnimation *strokeAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPShapeLayerStrokeEnd]; strokeAnimation.toValue = @(strokeEnd); strokeAnimation.springBounciness = 12.f; strokeAnimation.removedOnCompletion = NO; [self.colorMaskLayer pop_addAnimation:strokeAnimation forKey:@"layerStrokeAnimation"]; }