iOS刻度盘实现(swift)

Demo效果图:

效果图.png

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

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


进度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效果是这样:(颜色不重要)


遮盖Layer.png

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

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

效果就会变这样子:


遮盖后的样式.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源码在👆

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容

  • 表情是什么,我认为表情就是表现出来的情绪。表情可以传达很多信息。高兴了当然就笑了,难过就哭了。两者是相互影响密不可...
    Persistenc_6aea阅读 124,097评论 2 7
  • 16宿命:用概率思维提高你的胜算 以前的我是风险厌恶者,不喜欢去冒险,但是人生放弃了冒险,也就放弃了无数的可能。 ...
    yichen大刀阅读 6,032评论 0 4