iOS动画系列之八:使用CAShapeLayer绘画动态流量图1. CAShapeLayer2. 实战:绘制一个镂空图层动画3. 使用CAShapeLayer绘画动态流量图

这篇文章通过使用CAShapeLayer和UIBezierPath来画出一个动态显示剩余流量的小动画。

最终实现的效果如下:

Paste_Image.png

动态效果图:

shapeLayerAni.gif

1. CAShapeLayer

实际中,能够用CALayer完成的任务是比较少的,如果使用这个基础图层就能实现绝大部分的功能,咱们就没有必要再开启一个CAShapeLayer了嘛。

1.1 CAShapeLayer的优点

那CAShapeLayer到底有啥子优点嘛!

  • CAShapeLayer作为继承自CALayer的子类,当然可使用CALayer的所有属性。也就是说,爹有的它都有了。
  • CAShapeLayer是一个通过矢量图形而不是位图来绘制的图层子类。指定诸如颜色和线宽等属性,用path来定义想要绘制的图形,最后CAShapeLayer就自动渲染出来了。也就是说,CAShapeLayer不需要像普通CALayer一样创建一个寄宿图形。而且是矢量图形噢!!所以无论有多大,都不会占用太多的内存。
  • CAShapeLayer使用了硬件加速,绘制同一图形会比用CoreGraphics快很多。

1.2 基本属性

属性名

作用

path

图像的绘制路径,path不支持隐式动画

fillColor

填充path的颜色,或无填充。默认为不透明黑色。

fillRule

填充path的规则。选项是非零和偶奇。默认为非零。

lineCap

线端点类型

lineDashPattern

线性模版

lineDashPhase

线型模版的起点

lineJoin

线连接类型

lineWidth

线宽

miterLimit

最大斜接长度。

strokeColor

描边颜色

strokeStart

描边的起点

strokeEnd

描边的终点

1.3 属性解读

能看到这里,说明您已经不是一个没有任何基础的小白了。所以特别基础的属性就没必要解释一遍了。下面只是一个不常用或者立即起来稍微费点劲的属性。

  • lineDashPattern: 这是一个NSNumber的数组,索引从1开始记,奇数位数值表示实线长度,偶数位数值表示空白长度。系统会按照数值自动重复设置虚线。
  • miterLimit:最大斜接长度。斜接长度指的是在两条线交汇处和外交之间的距离。只有lineJoin属性为kCALineJoinMiter时miterLimit才有效。边角的角度越小,斜接长度就会越大。为了避免斜接长度过长,我们可以使用miterLimit属性。如果斜接长度超过miterLimit的值,边角会以lineJoin的“bevel”即kCALineJoinBevel类型来显示
  • strokeStart & strokeEnd : 描边的起始点位置。范围为0~1.

1.3.1 lineDashPattern画虚线

Paste_Image.png

basicLayer.lineDashPattern = [5,2,10,7]

这句话的意思是说这个虚线由四部分组成:

  1. 第一段实线长度为5
  2. 画完长度为5像素的实线之后,空2像素
  3. 空完2像素之后,再画10像素的实线
  4. 画完长度为10像素的实线之后,空7像素 然后重复这个数组中的数值,一直不停的绘画。

1.3.2 strokeStart & strokeEnd

strokeStart它表示描线开始的地方占总路径的百分比。默认值是0。 strokeEnd表示绘制结束的地方站总路径的百分比。默认值是1,如果小于等于strokeStart 则绘制不出任何内容。

手画一张图,解释一下啥意思:

Paste_Image.png

2. 实战:绘制一个镂空图层动画

做好后的效果如下:

Paste_Image.png

    fileprivate func hollowLayer(){
//        创建空心的layer
        let hollowLayer = CAShapeLayer()
        hollowLayer.bounds = CGRect(x: 0, y: 0, width: 100, height: 100)
        view.layer.addSublayer(hollowLayer)
        hollowLayer.position = view.center
        
//        最外面待圆角的方形path
        let squarePath = UIBezierPath.init(roundedRect: CGRect(x: 0, y: 0, width: 100, height: 100), cornerRadius: 5)
//        中间镂空的圆形path
        let hollowPath = UIBezierPath.init(ovalIn: CGRect(x: 10, y: 10, width: 80, height: 80))
        
        squarePath.append(hollowPath)
        hollowLayer.path = squarePath.cgPath

        hollowLayer.fillColor = UIColor.lightGray.cgColor
//        设置路径的填充模式为两个图形的非交集
        hollowLayer.fillRule = kCAFillRuleEvenOdd
    

     
//        创建进度layer
        let processSectorLayer = CAShapeLayer()
        view.layer.addSublayer(processSectorLayer)
        processSectorLayer.bounds = CGRect(x: 0, y: 0, width: 70, height: 70)
        processSectorLayer.position = view.center
        
//        进度的path
        let processSectorPath = UIBezierPath.init(arcCenter: CGPoint.init(x: 35, y: 35), radius: 17.5, startAngle: 0, endAngle: CGFloat.pi * 2, clockwise: true)
        
        
        processSectorLayer.path = processSectorPath.cgPath
        
        processSectorLayer.lineWidth = 35
        
//        进度的起点和结束位置,设置进度条修改这个值和结束数值就可以了
        processSectorLayer.strokeStart = 0.5
        processSectorLayer.strokeEnd = 0.75
        
        processSectorLayer.strokeColor = UIColor.lightGray.cgColor
        
        processSectorLayer.fillColor = UIColor.clear.cgColor
    }

3. 使用CAShapeLayer绘画动态流量图

有了上面对于CAShapeLayer 的基础训练,绘制一个动态的流量图就不是什么困难的事情了。 实现后的效果如下:

3.1 实现思路

1,创建一个view,用来展示进度圆环。 2,在进度的view上面添加一个layer,用来展示进度圆环底部灰色的圆环。 3,在灰色的圆环上面,添加一个layer,用来显示实际的进度。 4,创建一个定时器,定时器用来更新时时进度。

3.2 代码实现

在文章里面咱们只PO出来一些关键的代码,如果想查看源文件,可以自行下载源码哈。

3.2.1 懒加载进度圆环的shapeLayer

    //   进度条layer
    lazy var circleProgressLayer: CAShapeLayer = {
        
        let circleProgressLayer = CAShapeLayer()
        
        let circleBounds = CGRect(x: 0, y: 0, width: 250, height: 250)
        circleProgressLayer.bounds = circleBounds
        circleProgressLayer.position = CGPoint(x: circleBounds.width / 2, y: circleBounds.height / 2)
        

        let circleProgressPath = UIBezierPath.init(arcCenter: CGPoint(x: circleBounds.width / 2, y: circleBounds.height / 2), radius: circleBounds.height / 2, startAngle: 0, endAngle: CGFloat.pi * 2, clockwise: true)
        
        circleProgressLayer.strokeStart = 0
        circleProgressLayer.strokeEnd = 1
        circleProgressLayer.path = circleProgressPath.cgPath
        circleProgressLayer.lineWidth = 10
        circleProgressLayer.strokeColor = UIColor.init(colorLiteralRed: 0, green: 151, blue: 255, alpha: 1).cgColor
        
        circleProgressLayer.fillColor = UIColor.clear.cgColor
        return circleProgressLayer
    }()

3.2.2 添加定时器

        //开启定时器
        timer = Timer.scheduledTimer(timeInterval: 0.04, target: self, selector: #selector(progressShowNumber), userInfo: nil, repeats: true)

3.2.3 定时器的调用事件

// 定时器调用的方法
    @objc private func progressShowNumber(){
        
        if progressValue > expectValue - 1 && progressValue < expectValue {
            timer.invalidate()

            circleProgressLayer.strokeEnd = expectValue / 100
            progressLabel.text = "\(expectValue)%"
            return
        }
        if progressValue > expectValue {
            timer.invalidate()
            return
        }
        
//更新进度文字和进度条的strokeEnd
        circleProgressLayer.strokeEnd = CGFloat(progressValue) / 100
        progressLabel.text = "\(progressValue)%"

        progressValue += 1
    }

这两天人正好在San Francisco,抽空去San Jose苹果的大本营溜达溜达。到时候给大家放照哈。 源代码可以在这里下载。https://git.oschina.net/atypical/multAnimation.git

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏me的随笔

给图片添加文字水印

水印图片透明度设置和旋转(下面这段代码和上面一段代码都位于Watermark类中,因为代码量较大,所以分开来展示):

1704
来自专栏Android知识点总结

开源计划之--Android绘图库--LogicCanvas

Painter采用单例模式 优化原型模式,各Shape采用深拷贝来解决构造较长、繁琐的情况 比较new 对象和拷贝的效率问题,拷贝一点。具体见文:来谈谈Ja...

1523
来自专栏听雨堂

从MapX到MapXtreme2004[9]-标注的强调显示

        如果想要将一个选中的图元强调显示,用红色醒目的文字显示的话,我的思路如下:             1、不可能直接改原先的图元,所以必须要在一个...

2155
来自专栏听雨堂

从MapX到MapXtreme2004[9]-标注的强调显示

        如果想要将一个选中的图元强调显示,用红色醒目的文字显示的话,我的思路如下:             1、不可能直接改原先的图元,所以必须要在一个...

2326
来自专栏mukekeheart的iOS之旅

iOS学习——Quartz2D学习(1)

本文以问答形式主要讲述Quartz2D的相关内容,参考内容是网上下载的学习视频资料。

842
来自专栏everhad

[BOT] 一种android中实现“圆角矩形”的方法

内容简介 文章介绍ImageView(方法也可以应用到其它View)圆角矩形(包括圆形)的一种实现方式,四个角可以分别指定为圆角。思路是利用“Xfermode ...

3667
来自专栏everhad

Android自定义评分控件:RatingStarView

RatingStarView Android自定义的评分控件,类似RatingBar那样的,使用星星图标(full、half、empty)作为rating值的“...

4209
来自专栏九彩拼盘的叨叨叨

SVG 直线路径写法示例

大写字母表示到后面值为绝对值,小写字母表示后面值为相对当前点的值 画一条起点是(10, 10)终点点是 (20, 30) 的线

964
来自专栏Golang语言社区

【Go 语言社区】HTML5 canvas验证码识别

canvas 的历史这个 HTML 元素是为了客户端矢量图形而设计的。它自己没有行为,但却把一个绘图 API 展现给客户端 JavaScript 以使脚本能够把...

4904
来自专栏算法+

pixel art之 hqx 算法

在去年的时候,偶然看到hqx算法。 一个高质量的插值放大算法。 与双线性插值等插值算法相比,这个算法放大后对人眼保护相对比较好。 没有双线性插值看起来模糊,固然...

3726

扫码关注云+社区

领取腾讯云代金券