iOS刻度盘实现(swift)

Demo效果图:

iOS刻度盘实现(swift)_第1张图片
效果图.png

iOS刻度盘实现(swift)_第2张图片
gif效果图

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
    }()

只添加这些,界面效果是这样:


iOS刻度盘实现(swift)_第3张图片
进度Layer效果.png

接下来创建一个拱形的遮盖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效果是这样:(颜色不重要)


iOS刻度盘实现(swift)_第4张图片
遮盖Layer.png

接下来让progressLayer成为gradientLayer的遮盖:

        //设置进度Layer的遮盖
        gradientLayer.mask = progressLayer

效果就会变这样子:


iOS刻度盘实现(swift)_第5张图片
遮盖后的样式.png

基本上完成了

  • 接下来添加边框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源码在

感谢阅读
你的支持是我写作的唯一动力

关注我的文章微信公众号, 随时与你分享我的文章

iOS刻度盘实现(swift)_第6张图片
扫码关注我.jpg

你可能感兴趣的:(iOS刻度盘实现(swift))