渐变色进度条的两种绘制方案

在App开发中经常会用到渐变色进度条控件,而自定义进度条的实现也不难,下面提供了两种渐变色进度条的实现方案。

效果图如下:

第一种实现方案:使用图层layer实现

层级结构如图所示:

构建过程如下:

1.创建容器

容器创建方案上采用的是生成UIView的子视图:LabelProgressBar,

把LabelProgressBar当作一个类似容器的控件而面向客户端。

好处是:可以方便的使用LabelProgressBar在Xib,StoryBoard,代码中。

而如果用其他的方式,却做不到这样使用上的灵活。

2.添加渐变色图层到容器

添加渐变色到容器就比较容易了,代码如下:

//添加渐变色图层gradientLayer
let gradientLayer = CAGradientLayer()
gradientLayer.colors = [UIColor(hex: "4DABF4").cgColor, UIColor(hex: "9B30C1").cgColor]
//(I.e. [0,0] is the bottom-left corner of the layer, [1,1] is the top-right corner.)
gradientLayer.startPoint = CGPoint(x: 0, y: 0)
gradientLayer.endPoint = CGPoint(x: 1, y: 0)
gradientLayer.position = CGPoint(x: width*0.5, y: height*0.5)
gradientLayer.bounds = CGRect(origin: CGPoint.zero, size: CGSize(width: width, height: height))
self.layer.insertSublayer(gradientLayer, at: 0)

3.添加文字视图到容器

添加文字视图到容器也是常规操作,代码如下:

 lazy var contextLabel: UILabel = {
        let label = UILabel()
        label.text = " %"
        label.font = UIFont.systemFont(ofSize: 12)
        label.textColor = UIColor.white
        label.textAlignment = NSTextAlignment.center
        label.backgroundColor = UIColor.clear
        return label
    }()

 contextLabel.frame = CGRect(x: 0, y: 0, width: width, height: height)
self.addSubview(contextLabel)

进度变化过程

1.根据进度比例生成一个贝塞尔曲线

2.创建一个CALayer图层,将进度贝塞尔曲线赋值给它的path属性

3.拿到渐变色图层,将贝塞尔曲线图层赋值给它的mask属性

func maskLayer() {
    let temp = CGPoint(x: 0, y: 0)
    let bez = UIBezierPath()
    bez.move(to: temp)
    bez.addLine(to: CGPoint(x: progressWidth, y: 0))
    bez.addArc(withCenter: CGPoint(x: progressWidth, y: height*0.5), radius: height*0.5, startAngle: -CGFloat(M_PI_2), endAngle: CGFloat(M_PI_2), clockwise: true)
    bez.addLine(to: CGPoint(x: 0, y: height))
    bez.close()

    msLayer.path = bez.cgPath
    bottomLayer!.mask = msLayer
}

4.不同重复1-3的过程

这四个步骤也是不断调用maskLayer()方法的过程

第一种实现方案:使用CoreGraphics实现

主要实现思想:使用CoreGraphics,不断绘制

构建过程:

1.创建UIView的子类PartArcView

2.填充UIView提供的钩子函数func draw(_ rect: CGRect),draw方法内的实现为:

  a.在当前上下文中,从左到右绘制满线性渐变色内容

  b.绘制中间为镂空半圆弧的白色矩形内容,铺满上下文

  c.在圆弧的右半部分绘制灰色遮盖弧,去覆盖渐变色圆弧。达到进度不断变化的效果。

注意点:画弧时顺时针方向问题,上下文出栈入栈问题

上下文出栈入栈问题:

上下文对象是个单例对象,里面存储的是当前绘制面板的各种属性设置,包括(线色,线宽,填充色,折线圆角等)

如果不对当前上下文存储,就做修改,会修改整体属性,造成对下面绘制的污染。所以在绘制一段图像前先将当前上下文属性

入栈,等绘制完成后,在将刚才的原始上下文属性出栈,设置到上下文单例中来。如:代码中的绘制渐变色弧和灰色弧部分就

用到了上下文的出栈入栈操作(context?.saveGState(), context?.restoreGState())

画弧时顺时针方向问题:

CoreGraphics的坐标系弧度,与顺时针方向如图所示,注意不要用错了:

若要详情了解的话,请参考之前介绍过的一篇文章:https://www.cnblogs.com/zhou--fei/p/9859244.html

3.将进度值赋值PartArcView属性

4.调用setNeedsDisplay()

5.不断重复3-4步骤

部分代码如下:

let context = UIGraphicsGetCurrentContext()
//渐变色
let colorSpace = CGColorSpaceCreateDeviceRGB()
let locations:[CGFloat] = [0,1]
let startC = UIColor(hex: "EEA13A")
let endC = UIColor(hex: "B1283C")
let colors = [startC.cgColor,endC.cgColor]
let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: locations)
context?.drawLinearGradient(gradient!, start: CGPoint(x: 0, y: 0), end: CGPoint(x: rect.size.width, y: 0), options: CGGradientDrawingOptions.drawsBeforeStartLocation)

//渐变色弧
context?.saveGState()
context?.addRect(rect)
context?.move(to: CGPoint(x: width-edgeDistance, y: bigOuterRadius))
context?.addArc(center: arcCenter, radius: bigOuterRadius, startAngle: 0, endAngle: CGFloat(M_PI), clockwise: true)
context?.addArc(center: CGPoint(x: smailRadius+edgeDistance, y: arcCenter.y), radius: smailRadius, startAngle: CGFloat(M_PI), endAngle: CGFloat(M_PI*2), clockwise: true)
context?.addArc(center: arcCenter, radius: bigInnerRadius, startAngle: CGFloat(M_PI), endAngle: CGFloat(M_PI*2), clockwise: false)
context?.addArc(center: CGPoint(x: width-smailRadius-edgeDistance, y: arcCenter.y), radius: smailRadius, startAngle: CGFloat(M_PI), endAngle: CGFloat(M_PI*2), clockwise: true)
context?.setFillColor(UIColor.white.cgColor)
context?.fillPath()

//灰色弧
context?.restoreGState()
let context1 = UIGraphicsGetCurrentContext()
var endAng =  CGFloat(M_PI*2) - (_progressValue * CGFloat(M_PI))
context1?.move(to: CGPoint(x: width-edgeDistance, y: bigOuterRadius))
context1?.addArc(center: arcCenter, radius: bigOuterRadius, startAngle: 0, endAngle: endAng, clockwise: true)

let midSmallX: CGFloat = arcCenter.x + cos(endAng)*(bigOuterRadius-smailRadius)
let midSmallY: CGFloat = arcCenter.y + sin(endAng)*(bigOuterRadius-smailRadius)

context1?.addArc(center: CGPoint(x: midSmallX, y: midSmallY), radius: smailRadius, startAngle: endAng, endAngle: endAng-CGFloat(M_PI), clockwise: false)

context1?.addArc(center: arcCenter, radius: bigInnerRadius, startAngle: endAng, endAngle: CGFloat(M_PI*2), clockwise: false)
context1?.addArc(center: CGPoint(x: width-smailRadius-edgeDistance, y: arcCenter.y), radius: smailRadius, startAngle: CGFloat(M_PI), endAngle: CGFloat(M_PI*2), clockwise: true)
context1?.setFillColor(UIColor(hex: "e7e3e3").cgColor)
context1?.fillPath()

完整demo地址:https://github.com/zhfei/CoreAnimation

点击首页列表的进度条目录进入

原文地址:https://www.cnblogs.com/zhou--fei/p/10182351.html

时间: 2024-10-12 21:18:09

渐变色进度条的两种绘制方案的相关文章

javascript 进度条的几种方法

我们先看看最终效果: [url=169]169[/url] 第一步,基本构建基本的代码,看效果演示:<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"&g

Andorid自定义圆形渐变色进度条的从实现到开源

信自己也是一种信仰. 写在前面的话 3月初我在自定义控件概述中挖下的几个坑,前一段时间已经基本填完了,自定义控件的几种实现方式也分别写了demo来进行说明.今天我们来聊一聊如何把自己封装一个圆形渐变色进度条控件开源到github,并且上传到jcenter方便别人远程依赖.先看下效果图: 连接github并提交新项目 前提条件: 安装Git客户端(下载地址) 有GitHub账号 创建新项目并提交到Github: 在AndroidStudio中新建一个项目 配置Git:Settings -> Ver

【Android进度条】三种方式实现自定义圆形进度条ProgressBar

一.通过动画实现 定义res/anim/loading.xml如下: [html] view plaincopyprint? <?xml version="1.0" encoding="UTF-8"?> <animation-list android:oneshot="false" xmlns:android="http://schemas.android.com/apk/res/android"> &

Android自定义控件:进度条的四种实现方式

前三种实现方式代码出自: http://stormzhang.com/openandroid/2013/11/15/android-custom-loading/ (源码在最后) 最近一直在学习自定义控件,搜了许多大牛们Blog里分享的小教程,也上GitHub找了一些类似的控件进行学习.发现读起来都不太好懂,就想写这么一篇东西作为学习笔记吧. 一.控件介绍: 进度条在App中非常常见,例如下载进度.加载图片.打开文章.打开网页等等--都需要这么一个效果让用户知道我们的App正在读取,以构造良好的

Android自己定义控件:进度条的四种实现方式

前三种实现方式代码出自: http://stormzhang.com/openandroid/2013/11/15/android-custom-loading/ (源代码下载)http://download.csdn.net/detail/chaoyu168/9616035 近期一直在学习自己定义控件,搜了很多大牛们Blog里分享的小教程.也上GitHub找了一些类似的控件进行学习.发现读起来都不太好懂,就想写这么一篇东西作为学习笔记吧. 一.控件介绍: 进度条在App中非经常见,比例如以下载

Android自定义控件:进度条的四种实现方式(Progress Wheel的解析)(源码 + Demo)

Progress Wheel为GitHub热门项目,作者是:Todd-Davies,项目地址: https://github.com/Todd-Davies/ProgressWheel 前三种实现方式代码出自: http://stormzhang.com/openandroid/2013/11/15/android-custom-loading/ (源码在最后) 最近一直在学习自定义控件,搜了许多大牛们Blog里分享的小教程,也上GitHub找了一些类似的控件进行学习.发现读起来都不太好懂,就想

检验上传图片大小、尺寸、类型的两种实现方案

做图片上传功能时,我们经常会遇到一个问题就是,就是要对上传的图片进行一个校验,校验的东西包括图片的大小.尺寸(即宽和高)以及图片的类型. 今天我主要介绍两种方式来进行图片的校验,一种是在前端用js校验,另一种是放在服务器端校验.接下来我们来进行介绍 第一种:放在前端用js校验 下面直接贴源代码,注释也写在代码里面 1 <%@ page language="java" contenttype="text/html; charset=UTF-8" pageenco

(三)Redis两种持久化方案

Redis的持久化策略:2种 RDB方式的持久化是通过快照(snapshotting)完成的,当符合一定条件时Redis会自动将内存中的数据进行快照并持久化到硬盘.RDB是Redis默认采用的持久化方式. ---------aof:把所有的对redis的服务器进行修改的命令都存到一个文件里,命令的集合 rdb: 默认情况下,是快照rdb的持久化方式,将内存中的数据以快照的方式写入二进制文件中,默认的文件名是dump.rdb redis.conf配置: save 900 1 save 300 10

redis的两种持久化方案

人生在于折腾系列,网络,多线程等系列博客楼主还在继续折腾也不会放弃.这是全新的系列,缓存的知识其实并不仅仅在于简单的增删改查,我觉得有必要全面深入的学习一波.记录学习的过程与体悟. 2|0RDB 2|1什么是RDB 对redis中的数据执行周期性的持久化,通过配置文件中设置检查间隔时间与备份触发条件来对数据进行周期性的持久化 2|2RDB持久化的优点 RDB会生成多个数据文件,每个数据文件都代表了某一个时刻中redis的数据,这种多个数据文件的方式,非常适合做冷备份. RDB对redis对外提供