美文网首页iOS开发iOS开发动画
iOS动画系列之八:使用CAShapeLayer绘画动态流量图

iOS动画系列之八:使用CAShapeLayer绘画动态流量图

作者: 非典型技术宅 | 来源:发表于2017-03-05 14:42 被阅读2796次

    这篇文章通过使用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

    iOS动画系列之CAShapeLayer(Swift版)

    -----------------------华丽分割线,iOS动画系列全集链接-------------------------------------------------
    第一篇:iOS动画系列之一:通过实战学习CALayer和透视的原理。做一个带时分秒指针的时钟动画(上)
    第二篇:iOS动画系列之二:通过实战学习CALayer和透视的原理。做一个带时分秒指针的时钟动画。包含了OC和Swift两种源代码(下)
    第三篇:iOS动画系列之三:Core Animation。介绍了Core Animation的常用属性和方法。
    第四篇:CABasic Animation。iOS动画系列之四:基础动画之平移篇
    第五篇:CABasic Animation。iOS动画系列之五:基础动画之缩放篇&旋转篇
    第六篇:iOS动画系列之六:利用CABasic Animation完成带动画特效的登录界面
    第七篇:iOS动画系列之七:实现类似Twitter的启动动画
    第八篇:iOS动画系列之八:使用CAShapeLayer绘画动态流量图
    第九篇:iOS动画系列之九:实现点赞的动画及播放起伏指示器
    第十篇:实战系列:绘制过山车场景

    相关文章

      网友评论

      • 0206b277d36d:亲爱的 大神 为啥没有OC 版本 ,坐等更新 哈哈哈哈
        0206b277d36d:@hmj1993 谢谢 蛮好的
        hmj1993:https://github.com/hmj0930/LiuLiangJianCe.git
        hmj1993:我照着简主的思路写了个oc版本的 http://pan.baidu.com/share/link?shareid=57670845&uk=1546293196 希望可以帮到你
      • 大饼说科教:正好要用到

      本文标题:iOS动画系列之八:使用CAShapeLayer绘画动态流量图

      本文链接:https://www.haomeiwen.com/subject/eblwwttx.html