本文所有代碼均為swift,但即使你只是一個OCer,我保證你也不會看不懂。文章末尾附上demo地址急但。
上次用CAShapeLayer和UIBezierPath畫了一個企鵝(傳送門),這次還是用這兩樣?xùn)|西搞乏,封裝一個簡單實(shí)用的進(jìn)度條工具。先上一個效果圖:
先來整理一下我們需要做什么戒努,首先要有一個顯示進(jìn)度數(shù)字的label请敦,還要有一個進(jìn)度條,一個進(jìn)度條的底储玫,基本上就是這些侍筛。
第一步,我們需要創(chuàng)建一個繼承UIView的子類撒穷,就像下面:
class ProgressView:UIView {
override init(frame: CGRect) {
super.init(frame: frame);
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
然后我們需要的屬性或變量:
/// 進(jìn)度條
private var circleLayer:CAShapeLayer!
/// 顯示進(jìn)度數(shù)字的label
private var progressLabel:UILabel!
/// 背景條的寬度
private let backgroundLineWidth:CGFloat = 8;
/// 進(jìn)度條的寬度匣椰,比背景條稍寬,不至于露出下面的條端礼,丑
private let progressLineWidth:CGFloat = 12;
/// 進(jìn)度
var progress:CGFloat! = 0.0
然后在初始化方法中禽笑,我們先來使用UIBezierpath制作一個進(jìn)度條的圓形底,但是我們要先確定進(jìn)度條的半徑蛤奥,為了不超出這個view自身的大小佳镜,我們選寬高小的作為進(jìn)度條的直徑,但是UIBezierpath的半徑是從圓心到CAShapeLayer的線的寬度中心點(diǎn)的距離凡桥,所以我們需要減去背景寬度的一半:
let radius = (self.bounds.width > self.bounds.height ? self.bounds.height/2.0 : self.bounds.width/2.0) - backgroundLineWidth/2.0;
let layerCenter = CGPointMake(self.bounds.width/2.0, self.bounds.height/2.0);
// 畫一個圓形的path
let shadowBezierPath = UIBezierPath(arcCenter: layerCenter, radius: radius, startAngle: 0, endAngle: 2*CGFloat(M_PI), clockwise: true);
let shadowLayer = CAShapeLayer();
// 填充色
shadowLayer.fillColor = UIColor.clearColor().CGColor;
// 邊框色
shadowLayer.strokeColor = UIColor.blackColor().CGColor;
shadowLayer.frame = self.bounds;
// 邊框的寬度
shadowLayer.lineWidth = backgroundLineWidth;
shadowLayer.path = shadowBezierPath.CGPath;
self.layer.addSublayer(shadowLayer);
這樣蟀伸,我們來創(chuàng)建一個對象,看一下效果。
這樣我們的進(jìn)度條的底就算做好了啊掏,接下來我們做蓋在上面的進(jìn)度條蠢络,需要注意的是,即使進(jìn)度是0迟蜜,我們也需要展示一點(diǎn)進(jìn)度刹孔,不然太難看。
circleLayer = CAShapeLayer();
circleLayer.fillColor = UIColor.clearColor().CGColor;
circleLayer.strokeColor = UIColor(red: 214/255.0, green: 214/255.0, blue: 214/255.0, alpha: 1.0).CGColor;
/// 這個是設(shè)置線的頭部是圓角
circleLayer.lineCap = kCALineCapRound;
circleLayer.frame = self.bounds;
circleLayer.lineWidth = progressLineWidth;
self.layer.addSublayer(circleLayer);
progressLabel = UILabel();
progressLabel.font = UIFont.boldSystemFontOfSize(14);
progressLabel.textColor = UIColor.blackColor();
progressLabel.numberOfLines = 1;
progressLabel.textAlignment = NSTextAlignment.Center;
progressLabel.lineBreakMode = NSLineBreakMode.ByTruncatingTail;
self.addSubview(progressLabel);
/// 這是個記號
self.progressLabel.text = String(format: "%.0f", self.progress*100);
self.progressLabel.sizeToFit();
var labFrame = self.progressLabel.frame;
labFrame = CGRectMake((self.frame.width - self.progressLabel.frame.width)/2.0, (self.frame.height - self.progressLabel.frame.height)/2.0, self.progressLabel.frame.width, self.progressLabel.frame.height);
self.progressLabel.frame = labFrame;
var p = self.progress;
if (self.progress < 0.01) {
p = 0.01;
}
let bezierPath = UIBezierPath(arcCenter: CGPointMake(self.frame.width/2.0, self.frame.height/2.0), radius: radius, startAngle: CGFloat(-M_PI_2), endAngle: p*360/180*CGFloat(M_PI) - CGFloat(M_PI_2), clockwise: true);
self.circleLayer.path = bezierPath.CGPath;
效果如下:
接下來我們需要做的就是在改變progress的時候小泉,相應(yīng)的改變進(jìn)度的弧度芦疏,因此,我們先把以上代碼中的記號下面的代碼拉出來放一個方法里微姊,在progress的didSet方法里酸茴,調(diào)用這個方法即可,比如這個方法叫setProgress:
/// 進(jìn)度
var progress:CGFloat! = 0.0 {
didSet {
if (progress >= 1) {
progress = 1;
}
self.setProgress();
}
}
到這兢交,這個進(jìn)度條控件基本已經(jīng)做好了薪捍,但是還不夠完善,比如再用NSURLSession下載的代理中配喳,因?yàn)橄螺d的代理方法并不在主線程中酪穿,在代理方法中直接改變progress,就會有問題晴裹,我們可以把setProgress中的代碼放到主線程中被济。
dispatch_async(dispatch_get_main_queue()) {
// setProgress
}
下篇預(yù)告: