漸變色進度條的兩種繪制方案
阿新 • • 發佈:2018-12-27
val hit return rgb 四個步驟 完成 forest 之前 nbsp 在App開發中經常會用到漸變色進度條控件,而自定義進度條的實現也不難,下面提供了兩種漸變色進度條的實現方案。
效果圖如下:
3.添加文字視圖到容器
添加文字視圖到容器也是常規操作,代碼如下:
第一種實現方案:使用圖層layer實現
層級結構如圖所示:
構建過程如下:
1.創建容器 容器創建方案上采用的是生成UIView的子視圖:LabelProgressBar, 把LabelProgressBar當作一個類似容器的控件而面向客戶端。 好處是:可以方便的使用LabelProgressBar在Xib,StoryBoard,代碼中。 而如果用其他的方式,卻做不到這樣使用上的靈活。 2.添加漸變色圖層到容器 添加漸變色到容器就比較容易了,代碼如下://添加漸變色圖層gradientLayer
let gradientLayer = CAGradientLayer()
gradientLayer.colors = [UIColor(hex: "4DABF4").cgColor, UIColor(hex: "9B30C1").cgColor]
//(I.e. [0,0] is the bottom-left corner of the layer, [1,1] is the top-right corner.)
gradientLayer.startPoint = CGPoint(x: 0, y: 0)
gradientLayer.endPoint = CGPoint(x: 1, y: 0)
gradientLayer.position = CGPoint(x: width*0.5, y: height*0.5)
gradientLayer.bounds = CGRect(origin: CGPoint.zero, size: CGSize(width: width, height: height))
self.layer.insertSublayer(gradientLayer, at: 0)
lazy var contextLabel: UILabel = { let label = UILabel() label.text = " %" label.font = UIFont.systemFont(ofSize: 12) label.textColor = UIColor.white label.textAlignment = NSTextAlignment.center label.backgroundColor進度變化過程 1.根據進度比例生成一個貝塞爾曲線 2.創建一個CALayer圖層,將進度貝塞爾曲線賦值給它的path屬性 3.拿到漸變色圖層,將貝塞爾曲線圖層賦值給它的mask屬性= UIColor.clear return label }() contextLabel.frame = CGRect(x: 0, y: 0, width: width, height: height) self.addSubview(contextLabel)
func maskLayer() { let temp = CGPoint(x: 0, y: 0) let bez4.不同重復1-3的過程 這四個步驟也是不斷調用maskLayer()方法的過程 第一種實現方案:使用CoreGraphics實現 主要實現思想:使用CoreGraphics,不斷繪制 構建過程: 1.創建UIView的子類PartArcView 2.填充UIView提供的鉤子函數func draw(_ rect: CGRect),draw方法內的實現為: a.在當前上下文中,從左到右繪制滿線性漸變色內容 b.繪制中間為鏤空半圓弧的白色矩形內容,鋪滿上下文 c.在圓弧的右半部分繪制灰色遮蓋弧,去覆蓋漸變色圓弧。達到進度不斷變化的效果。 註意點:畫弧時順時針方向問題,上下文出棧入棧問題 上下文出棧入棧問題: 上下文對象是個單例對象,裏面存儲的是當前繪制面板的各種屬性設置,包括(線色,線寬,填充色,折線圓角等) 如果不對當前上下文存儲,就做修改,會修改整體屬性,造成對下面繪制的汙染。所以在繪制一段圖像前先將當前上下文屬性 入棧,等繪制完成後,在將剛才的原始上下文屬性出棧,設置到上下文單例中來。如:代碼中的繪制漸變色弧和灰色弧部分就 用到了上下文的出棧入棧操作(context?.saveGState(), context?.restoreGState())= UIBezierPath() bez.move(to: temp) bez.addLine(to: CGPoint(x: progressWidth, y: 0)) bez.addArc(withCenter: CGPoint(x: progressWidth, y: height*0.5), radius: height*0.5, startAngle: -CGFloat(M_PI_2), endAngle: CGFloat(M_PI_2), clockwise: true) bez.addLine(to: CGPoint(x: 0, y: height)) bez.close() msLayer.path = bez.cgPath bottomLayer!.mask = msLayer }
畫弧時順時針方向問題:
CoreGraphics的坐標系弧度,與順時針方向如圖所示,註意不要用錯了:
若要詳情了解的話,請參考之前介紹過的一篇文章:https://www.cnblogs.com/zhou--fei/p/9859244.html3.將進度值賦值PartArcView屬性 4.調用setNeedsDisplay() 5.不斷重復3-4步驟 部分代碼如下:
let context = UIGraphicsGetCurrentContext() //漸變色 let colorSpace = CGColorSpaceCreateDeviceRGB() let locations:[CGFloat] = [0,1] let startC = UIColor(hex: "EEA13A") let endC = UIColor(hex: "B1283C") let colors = [startC.cgColor,endC.cgColor] let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: locations) context?.drawLinearGradient(gradient!, start: CGPoint(x: 0, y: 0), end: CGPoint(x: rect.size.width, y: 0), options: CGGradientDrawingOptions.drawsBeforeStartLocation) //漸變色弧 context?.saveGState() context?.addRect(rect) context?.move(to: CGPoint(x: width-edgeDistance, y: bigOuterRadius)) context?.addArc(center: arcCenter, radius: bigOuterRadius, startAngle: 0, endAngle: CGFloat(M_PI), clockwise: true) context?.addArc(center: CGPoint(x: smailRadius+edgeDistance, y: arcCenter.y), radius: smailRadius, startAngle: CGFloat(M_PI), endAngle: CGFloat(M_PI*2), clockwise: true) context?.addArc(center: arcCenter, radius: bigInnerRadius, startAngle: CGFloat(M_PI), endAngle: CGFloat(M_PI*2), clockwise: false) context?.addArc(center: CGPoint(x: width-smailRadius-edgeDistance, y: arcCenter.y), radius: smailRadius, startAngle: CGFloat(M_PI), endAngle: CGFloat(M_PI*2), clockwise: true) context?.setFillColor(UIColor.white.cgColor) context?.fillPath() //灰色弧 context?.restoreGState() let context1 = UIGraphicsGetCurrentContext() var endAng = CGFloat(M_PI*2) - (_progressValue * CGFloat(M_PI)) context1?.move(to: CGPoint(x: width-edgeDistance, y: bigOuterRadius)) context1?.addArc(center: arcCenter, radius: bigOuterRadius, startAngle: 0, endAngle: endAng, clockwise: true) let midSmallX: CGFloat = arcCenter.x + cos(endAng)*(bigOuterRadius-smailRadius) let midSmallY: CGFloat = arcCenter.y + sin(endAng)*(bigOuterRadius-smailRadius) context1?.addArc(center: CGPoint(x: midSmallX, y: midSmallY), radius: smailRadius, startAngle: endAng, endAngle: endAng-CGFloat(M_PI), clockwise: false) context1?.addArc(center: arcCenter, radius: bigInnerRadius, startAngle: endAng, endAngle: CGFloat(M_PI*2), clockwise: false) context1?.addArc(center: CGPoint(x: width-smailRadius-edgeDistance, y: arcCenter.y), radius: smailRadius, startAngle: CGFloat(M_PI), endAngle: CGFloat(M_PI*2), clockwise: true) context1?.setFillColor(UIColor(hex: "e7e3e3").cgColor) context1?.fillPath()完整demo地址:https://github.com/zhfei/CoreAnimation 點擊首頁列表的進度條目錄進入
漸變色進度條的兩種繪制方案