Demo效果图:
github地址
最近看到一个很不错的有关UI的OC版Demo
仿照他的Demo自己写了这个swift版本
也是一番了学习
View的用法:
把HXScaleView拖入项目
创建实例:
let proView = HXScaleView.init(frame: CGRect.init(x: 0, y: 100, width: UIScreen.main.bounds.width, height: 300))
proView.backgroundColor = UIColor.lightGray
给他Value:
//取值是0-1
progressView.progress = 0.32
实现过程:
- 进度View分为以下几部分:
上下白色边框Layer
进度Layer
遮盖Layer
刻度Layer
刻度值Label
数值Label -
先介绍核心的进度Layer和遮盖Layer
进度Layer的创建代码:
lazy var gradientLayer: CAGradientLayer = {
let graLayer = CAGradientLayer.init()
graLayer.frame = self.bounds
//色值变化
graLayer.colors = [
UIColor.init(red: 0.09, green: 0.58, blue: 0.15, alpha: 1).cgColor,
UIColor.init(red: 0.20, green: 0.63, blue: 0.25, alpha: 1).cgColor,
UIColor.init(red: 0.60, green: 0.82, blue: 0.22, alpha: 1).cgColor,
UIColor.init(red: 0.97, green: 0.65, blue: 0.22, alpha: 1).cgColor,
UIColor.init(red: 0.96, green: 0.08, blue: 0.10, alpha: 1).cgColor
]
graLayer.locations = [0,0.25,0.5,0.75,1]
//开始位置和结束位置
graLayer.startPoint = CGPoint.init(x: 0, y: 0)
graLayer.endPoint = CGPoint.init(x: 1, y: 0)
return graLayer
}()
只添加这些,界面效果是这样:
接下来创建一个拱形的遮盖Layer:
//遮盖layer
lazy var progressLayer: CAShapeLayer = {
//拱形路径
let bezierPath = UIBezierPath.init(arcCenter: self.center, radius: 115, startAngle: -(CGFloat.pi), endAngle: 0, clockwise: true)
let proLayer = CAShapeLayer.init()
proLayer.lineWidth = 60.0
//为了方便区分 设置成红色, 并不影响遮盖
proLayer.strokeColor = UIColor.red.cgColor
proLayer.fillColor = UIColor.clear.cgColor
proLayer.path = bezierPath.cgPath
proLayer.strokeStart = 0.0
proLayer.strokeEnd = 0.0
return proLayer
}()
遮盖Layer效果是这样:(颜色不重要)
接下来让progressLayer成为gradientLayer的遮盖:
//设置进度Layer的遮盖
gradientLayer.mask = progressLayer
效果就会变这样子:
基本上完成了
-
接下来添加边框Layer:
let path = UIBezierPath.init(arcCenter: center, radius: radius, startAngle: -CGFloat.pi, endAngle: 0, clockwise: true)
let curve = CAShapeLayer.init()
curve.lineWidth = 4.0
curve.fillColor = UIColor.clear.cgColor
curve.strokeColor = UIColor.white.cgColor
curve.path = path.cgPath
self.layer.addSublayer(curve)
没啥好说的,很简单的CAShapeLayer
-
然后是刻度Layer:
let perAngle = CGFloat.pi / 50.0 //一刻度的弧度
let calWidth = perAngle / 10.0 //刻度线的宽度
for index in 1..<50{
let startAngel = -CGFloat.pi + perAngle * CGFloat(index)
let endAngel = startAngel + calWidth
let path = UIBezierPath.init(arcCenter: center, radius: 140, startAngle: startAngel, endAngle: endAngel, clockwise: true)
//每一个刻度 都是一个小圆弧(每个小圆弧都是一个shapeLayer)
let shapeLayer = CAShapeLayer.init()
if index % 5 == 0 {
shapeLayer.strokeColor = UIColor.white.cgColor
shapeLayer.lineWidth = 10.0
//计算刻度值Label位置
let labelRadius : CGFloat = 125.0 //label中心点的半径
let x = labelRadius * cos(-startAngel)
let y = labelRadius * sin(-startAngel)
let point = CGPoint.init(x: center.x + x, y: center.y - y)
//刻度值label
let scaleLabel = UILabel.init(frame: CGRect.init(x: point.x - 10, y: point.y - 10, width: 20, height: 20))
scaleLabel.text = "\(index * 2)"
scaleLabel.font = UIFont.systemFont(ofSize: 10)
scaleLabel.textColor = UIColor.white
scaleLabel.textAlignment = NSTextAlignment.center
self.addSubview(scaleLabel)
}else{
shapeLayer.strokeColor = UIColor.white.cgColor
shapeLayer.lineWidth = 5.0
}
shapeLayer.path = path.cgPath
self.layer.addSublayer(shapeLayer)
}
-
最后是动画效果:
由于我们创建的Lyaer添加到View上后
都不是View的根Layer
所以可以直接做隐式动画
在view的progress值被修改的时候:
//刻度值
var progress : CGFloat = 0.0 {
didSet{
print("我要把数据修改成\(progress)")
//跨度值
let gapValue = progress - oldValue
//刻度盘整个跨度设置为3秒, 根据当前跨度来确定需要的动画时间
let time = fabsf(Float(gapValue * 3.0))
//刻度盘的隐式动画
CATransaction.begin()
CATransaction.setDisableActions(false)
CATransaction.setAnimationDuration(CFTimeInterval(time))
CATransaction.setAnimationTimingFunction(CAMediaTimingFunction.init(name: kCAMediaTimingFunctionLinear))
progressLayer.strokeEnd = progress
CATransaction.commit()
//valueLabel的数值变化
let anima = CATransition.init()
anima.duration = 1.0
valueLabel.text = String(format: "%.1f", progress * 100)
valueLabel.layer.add(anima, forKey: nil)
}
}
github源码在👆
感谢阅读
你的支持是我写作的唯一动力