一般成長值類型的進度條都是純色的贩幻,比如這樣的:
純色的進度條無論用layer還是view,只要計算好比例就是很好做的峭火。
我們的需求是自定義的進度條是這樣的:
從圖中可以看出我們的UI進度條是紅粉相間的被芳,而且單個的還是平行四邊形襟企。在實現方案上肪获,考慮了下寝凌,就放棄了使用切圖imageView實現的思路,因為進度條的長度代表當前值和總值的比例孝赫,就算是平行四邊形也有可能不是完整的四邊形较木,使用切圖的方式是不好實現的。那么我們只能通過layer來實現了寒锚。
確定了基本的方案劫映,還有幾個問題:
1.如何實現粉紅相間的效果
2.如何繪制每個平行四邊形、進度條末端不完整的四邊形以及進度條最后的弧線
3.這么大的圖標占了一小段的進度條怎么辦
4.怎么知道進度條要畫多長刹前,平行四邊形要畫多少個,以及進度條末端不完整的四邊形的大小
現在我們來一一解答這些問題:
1.純色的進度條可以很容易的用layer實現雌桑,但是多個顏色的不容易實現喇喉,是因為layer只能有一種fillColor或者strokeColor,設置兩種fillColor或者strokeColor會以最后的設置來繪制。我也想過把紅色校坑、粉色分別作為fillColor和strokeColor,但是想想就放棄了拣技,路徑實現不好畫。那我們如果用兩個layer分別是粉色耍目、紅色的fillColor是不是就可以實現了膏斤?理論上是可以的。
- (CAShapeLayer *)redLayer
{
if (!_redLayer) {
_redLayer = [CAShapeLayer layer];
_redLayer.fillColor = HKColor(252, 85, 108, 1).CGColor;
_redLayer.strokeColor = HKColor(255, 153, 167, 1).CGColor;
_redLayer.lineWidth = 1;
}
return _redLayer;
}
- (CAShapeLayer *)pinkLayer
{
if (!_pinkLayer) {
_pinkLayer = [CAShapeLayer layer];
_pinkLayer.fillColor = HKColor(255, 153, 167, 1).CGColor;
_pinkLayer.strokeColor = HKColor(255, 153, 167, 1).CGColor;
_pinkLayer.lineWidth = 1;
}
return _pinkLayer;
}
2.四邊形可以看做是一條條直線組成邪驮,弧線可以用半圓來近似繪制,這兩種繪制都可以用貝塞爾曲線很容易的實現莫辨,如下所示:
[path moveToPoint:CGPointMake(0+_singleSquareWidth*(i-1), _singleSquareHeight)];
[path addLineToPoint:CGPointMake(0+_singleSquareOffset+_singleSquareWidth*(i-1), 0)];
[path addLineToPoint:CGPointMake(0+_singleSquareOffset+_singleSquareWidth*(i-1)+_singleSquareWidth,0)];
[path addLineToPoint:CGPointMake(0+_singleSquareWidth+_singleSquareWidth*(i-1),_singleSquareHeight)];
[path addLineToPoint:CGPointMake(0+_singleSquareWidth*(i-1), _singleSquareHeight)];
[redPath addArcWithCenter:CGPointMake(0, _singleSquareHeight/2) radius:_singleSquareHeight/2 startAngle:M_PI_2 endAngle:M_PI_2*3 clockwise:YES];
這兩種都是貝塞爾曲線的基本用法
3.由于我們的圖標比較大,所以占據的進度條的長度是不可以忽略不計的,所以我們需要圖標占位大小一個值沮榜,方便我們做進度條進度的比例剔除掉這部分的長度盘榨,避免出現進度條進度和進度值不符的現象。
4.要確定進度條畫多長我們要先確定蟆融,進度值是在當前哪一段進度中草巡,就是我的代碼中定義的index屬性,從0開始型酥。
if (self.currentGrowUpValue == [[self.growUpValueArray firstObject] integerValue]) {
self.index = 0;
return;
}
for (NSInteger i = 0;i<self.growUpValueArray.count ; i++) {
NSInteger indexValue = [self.growUpValueArray[i] integerValue];
if (self.currentGrowUpValue >= indexValue) {
self.index = i;
}else{
return;
}
}
確定了index之后我們再確定進度條的長度山憨,如果進度值為0我們是不繪制進度條的,進度值等于最大值就是繪制滿進度條弥喉,其他情況需要按比例計算進度條長度萍歉。
if (self.index == self.growUpValueArray.count - 1) {
self.processLayerWidth = _lineWidth;
}else{
CGFloat lastScale = (CGFloat)(self.currentGrowUpValue - [self.growUpValueArray[self.index] integerValue])/(CGFloat)([self.growUpValueArray[self.index+1] integerValue]- [self.growUpValueArray[self.index] integerValue]);
self.processLayerWidth = (self.singleLineWidth + self.iconPlaceHolderPT)*self.index + self.singleLineWidth*lastScale+self.iconPlaceHolderPT/2 - (lastScale == 0? self.iconPlaceHolderPT/2:0);
}
這里進度條的計算是最核心的部分,我的繪制原則是如果lastScale是0档桃,就繪制到占位的圖標中心位置結束枪孩,如果lastScale>0,要從占位圖標的最右側開始繪制,這就是我再上面說的藻肄,剔除掉占位圖標的大小蔑舞,不能算做計算進度比例的基數,也不能算作長度嘹屯,之所以lastScale = 0攻询,要繪制到占位圖標中心,是因為占位圖標多數有透明背景州弟,只繪制到圖標左側有進度不滿的既視感钧栖。
有了進度條的長度我們就很好計算平行四邊形的個數了
NSInteger singleCount = _processLayerWidth/self.singleSquareWidth;
大家都能明白這里是不能整除的,剩下的部分就是進度條末端的長度了婆翔,然后再加上個半圓就完成了
[path moveToPoint:CGPointMake(_layerLeft+(singleCount-1)*self.singleSquareWidth + self.singleSquareOffset, +_layerTop)];
[path addLineToPoint:CGPointMake(_layerLeft+_processLayerWidth, +_layerTop)];
[path addArcWithCenter:CGPointMake(_layerLeft+_processLayerWidth, _singleSquareHeight/2+_layerTop) radius:_singleSquareHeight/2 startAngle:-M_PI_2 endAngle:M_PI_2 clockwise:YES];
[path addLineToPoint:CGPointMake(_layerLeft+(singleCount-1)*self.singleSquareWidth, _singleSquareHeight+_layerTop)];
方案二:切整個紅粉相間的進度條的圖拯杠,然后黃色部分動態(tài)繪制剩下長度的layer
這種比較簡單,就不用貼代碼了啃奴。
這里是GitHub地址:https://github.com/SunshineTeemo/SSCustomProcessView/tree/master
請大家多指教潭陪!