android 彩虹进度条自定义view实现

实现一个彩虹色进度条功能,不说明具体用途大家应该能猜到。想找别人造的轮子,但是没有合适的,所以决定自己实现一个。
相关知识
android 自定义view
LinearGradient 线性渐变
实现步骤
自定义view
自定义一个TmcView类继承View
重写两个构造方法。构造方法一共有4个,这里边重写两个
重写ongSizeChanged方法,用来获取控件宽、高,来计算内部组件尺寸。
重写onDraw方法,里边要描画背景drawBackground,分段数据drawSection,和seekbar图片drawImage。
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;import androidx.annotation.Nullable;import java.util.List;public class TmcView extends View {public TmcView(Context context) {super(context);}public TmcView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);drawBackground(canvas);drawSection(canvas);drawImage(canvas);}/*** 画背景* @param canvas 画布*/private void drawBackground(Canvas canvas) {}/*** 画分段数据* @param canvas 画布*/private void drawSection(Canvas canvas) {}/*** 画图片* @param canvas 画布*/private void drawImage(Canvas canvas) {}/*** 更新view* @param total 总长度* @param rest 剩余长度* @param sections 分段数据*/public void updateView(int total, int rest, List<SectionData> sections){}
实现几个重构方法
标注:
整体宽度为图片宽度44px
背景条宽度30px,外边距7px,圆角15px
带颜色的条宽度20xp,外边距5px,圆角15px
自定义view的坐标轴是以view的左上角位置为原点,向右为x轴正方向,向下为y轴正方向

在视图中用RectF创建背景,和颜色条,并在onSizeChanged中设置尺寸
public class TmcView extends View {private final RectF backgroundRectF = new RectF();private final RectF colorRectF = new RectF();public TmcView(Context context) {super(context);}public TmcView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);//设置矩形 left top right bottom 左上右下点的值 按照标注计算得出backgroundRectF.set(7, 0, 37, h);colorRectF.set(12, 5, 32, h-5);}...
}
绘制背景条

实现drawBackground方法,画背景需要一根画笔Paint 为了避免重复创建,声明为成员变量
public class TmcView extends View {/*背景画笔*/private final Paint backPaint = new Paint(Paint.ANTI_ALIAS_FLAG);private final RectF backgroundRectF = new RectF();private final RectF colorRectF = new RectF();public TmcView(Context context) {super(context);}public TmcView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);//设置矩形 left top right bottom 左上右下点的值 按照标注计算得出backgroundRectF.set(7, 0, 37, h);colorRectF.set(12, 5, 32, h-5);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);drawBackground(canvas);drawSection(canvas);drawImage(canvas);}/*** 画背景* @param canvas 画布*/private void drawBackground(Canvas canvas) {backPaint.setStyle(Paint.Style.FILL);backPaint.setAntiAlias(true); //抗锯齿backPaint.setColor(Color.parseColor("#FFFFFF"));//画圆角矩形,15为圆角的角度canvas.drawRoundRect(backgroundRectF, 15, 15, backPaint);}
...
}
布局中加入TmcView
<com.bigxuan.tesapp.view.TmcViewandroid:id="@+id/tmc"android:layout_width="44px"android:layout_height="690px"android:layout_marginEnd="1230px"android:layout_marginBottom="100px"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"/>
绘制颜色条
![]()
实现drawSection方法,这里要用到线性渐变LinearGradient
LinearGradient 简单说,指定每一段的颜色和位置百分比,就能实现每一段显示不同颜色。
但它默认是渐变色,要想不变就在每一段的开始和结束位置都设置相同的颜色。
再创建一个画笔 Paint,画颜色条
public class TmcView extends View {private final Paint backPaint = new Paint(Paint.ANTI_ALIAS_FLAG);private final Paint colorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);private final RectF backgroundRectF = new RectF();private final RectF colorRectF = new RectF();public TmcView(Context context) {super(context);}public TmcView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);//设置矩形 left top right bottom 左上右下点的值 按照标注计算得出backgroundRectF.set(7, 0, 37, h);colorRectF.set(12, 5, 32, h-5);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);drawBackground(canvas);drawSection(canvas);drawImage(canvas);}/*** 画背景* @param canvas 画布*/private void drawBackground(Canvas canvas) {backPaint.setStyle(Paint.Style.FILL);backPaint.setAntiAlias(true); //抗锯齿backPaint.setColor(Color.parseColor("#FFFFFF"));//画圆角矩形,15为圆角的角度canvas.drawRoundRect(backgroundRectF, 15, 15, backPaint);}/*** 画分段数据* @param canvas 画布*/private void drawSection(Canvas canvas) {int[] colorArray = {Color.parseColor("#FF0000"), Color.parseColor("#FF0000"),Color.parseColor("#00FF00"), Color.parseColor("#00FF00"),Color.parseColor("#0000FF"), Color.parseColor("#0000FF")};float[] positionArray = {0f, 0.2f,0.2f, 0.6f,0.6f, 1f};colorPaint.setStyle(Paint.Style.FILL);colorPaint.setAntiAlias(true);//指定渐变色方向x轴方向不变,沿y方向渐变,渐变范围为 颜色条高度colorPaint.setShader(new LinearGradient(0, 0, 0, colorRectF.bottom, colorArray, positionArray, Shader.TileMode.REPEAT));canvas.drawRoundRect(colorRectF,15, 15, colorPaint);}...
}
绘制进度图片

app加入图片资源,根据资源id获取bitmap对象,绘制。
需要注意的是,坐标轴的顶点在左上角,绘制图片时也是以图片左上顶点位置做定位,图片位置是view的高度减掉图片的高度,才能显示在正确位置。
public class TmcView extends View {private Context context;private final Paint backPaint = new Paint(Paint.ANTI_ALIAS_FLAG);private final Paint colorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);private final RectF backgroundRectF = new RectF();private final RectF colorRectF = new RectF();/*图片资源id*/private int imgResId;/*图片位置*/private int imgPos;public TmcView(Context context) {super(context);}public TmcView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);this.context = context;this.imgResId = R.drawable.icon_seekbar_day;}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);//设置矩形 left top right bottom 左上右下点的值 按照标注计算得出backgroundRectF.set(7, 0, 37, h);colorRectF.set(12, 5, 32, h-5);imgPos = h - 44; // 设置一个初始位置}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);drawBackground(canvas);drawSection(canvas);drawImage(canvas);}/*** 画背景* @param canvas 画布*/private void drawBackground(Canvas canvas) {backPaint.setStyle(Paint.Style.FILL);backPaint.setAntiAlias(true); //抗锯齿backPaint.setColor(Color.parseColor("#FFFFFF"));//画圆角矩形,15为圆角的角度canvas.drawRoundRect(backgroundRectF, 15, 15, backPaint);}/*** 画分段数据* @param canvas 画布*/private void drawSection(Canvas canvas) {int[] colorArray = {Color.parseColor("#FF0000"), Color.parseColor("#FF0000"),Color.parseColor("#00FF00"), Color.parseColor("#00FF00"),Color.parseColor("#0000FF"), Color.parseColor("#0000FF")};float[] positionArray = {0f, 0.2f,0.2f, 0.6f,0.6f, 1f};colorPaint.setStyle(Paint.Style.FILL);colorPaint.setAntiAlias(true);//指定渐变色方向x轴方向不变,沿y方向渐变,渐变范围为 颜色条高度colorPaint.setShader(new LinearGradient(0, 0, 0, colorRectF.bottom, colorArray, positionArray, Shader.TileMode.REPEAT));canvas.drawRoundRect(colorRectF,15, 15, colorPaint);}/*** 画图片* @param canvas 画布*/private void drawImage(Canvas canvas) {Bitmap bitmap = initBitmap(imgResId);canvas.save();canvas.translate(0, 0);canvas.drawBitmap(bitmap, 0, imgPos, null);canvas.restore();}/*** 通过资源id 创建bitmap* @param resId 资源id* @return*/private Bitmap initBitmap(int resId) {Bitmap originalBmp = BitmapFactory.decodeResource(context.getResources(), resId);return Bitmap.createScaledBitmap(originalBmp, 44, 44, true);}
...
}
公共方法
暴露方法用来更新进度updateView
定义一个图片有效的运动距离为view高度减掉图片高度,函数参数为总距离和剩余距离,计算百分比后乘以有效运动距离得出图片描画位置。最后调用invalidate方法刷新view
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.View;import androidx.annotation.Nullable;import com.navinfo.tesapp.R;import java.util.List;public class TmcView extends View {private Context context;private final Paint backPaint = new Paint(Paint.ANTI_ALIAS_FLAG);private final Paint colorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);private final RectF backgroundRectF = new RectF();private final RectF colorRectF = new RectF();/*图片资源id*/private int imgResId;/*图片位置*/private int imgPos;/*图片有效的运动距离*/private int imgValidHeight;public TmcView(Context context) {super(context);}public TmcView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);this.context = context;this.imgResId = R.drawable.icon_seekbar_day;}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);//设置矩形 left top right bottom 左上右下点的值 按照标注计算得出backgroundRectF.set(7, 0, 37, h);colorRectF.set(12, 5, 32, h-5);imgValidHeight = h - 44;imgPos = h - 44; // 设置一个初始位置}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);drawBackground(canvas);drawSection(canvas);drawImage(canvas);}/*** 画背景* @param canvas 画布*/private void drawBackground(Canvas canvas) {backPaint.setStyle(Paint.Style.FILL);backPaint.setAntiAlias(true); //抗锯齿backPaint.setColor(Color.parseColor("#FFFFFF"));//画圆角矩形,15为圆角的角度canvas.drawRoundRect(backgroundRectF, 15, 15, backPaint);}/*** 画分段数据* @param canvas 画布*/private void drawSection(Canvas canvas) {int[] colorArray = {Color.parseColor("#FF0000"), Color.parseColor("#FF0000"),Color.parseColor("#00FF00"), Color.parseColor("#00FF00"),Color.parseColor("#0000FF"), Color.parseColor("#0000FF")};float[] positionArray = {0f, 0.2f,0.2f, 0.6f,0.6f, 1f};colorPaint.setStyle(Paint.Style.FILL);colorPaint.setAntiAlias(true);//指定渐变色方向x轴方向不变,沿y方向渐变,渐变范围为 颜色条高度colorPaint.setShader(new LinearGradient(0, 0, 0, colorRectF.bottom, colorArray, positionArray, Shader.TileMode.REPEAT));canvas.drawRoundRect(colorRectF,15, 15, colorPaint);}/*** 画图片* @param canvas 画布*/private void drawImage(Canvas canvas) {Bitmap bitmap = initBitmap(imgResId);canvas.save();canvas.translate(0, 0);canvas.drawBitmap(bitmap, 0, imgPos, null);canvas.restore();}/**** @param resId* @return*/private Bitmap initBitmap(int resId) {Bitmap originalBmp = BitmapFactory.decodeResource(context.getResources(), resId);return Bitmap.createScaledBitmap(originalBmp, 44, 44, true);}/*** 更新view* @param total 总长度* @param rest 剩余长度* @param sections 分段数据*/public void updateView(int total, int rest, List<SectionData> sections){float percent = (1f * rest) / total;//防止溢出if(percent < 0){return;}imgPos = (int)(percent * imgValidHeight);invalidate();}
}
updateView方法还有第三个参数,是用来传出颜色条不同段的颜色和百分比数据的。根据此数据来更新颜色条。这里需要根据业务不同自己实现,我这里就不写了。
总结
大家可能看出来了,这个视图是用来展示导航中不同路段交通情况和当前车辆进度用的。自定义view中可以在构造方法中获取一些自定义属性,像背景条和颜色条的边距、圆角这些都可以定义到xml中,因为只适配一种屏幕尺寸所以也没有做多尺寸适配。以前也没有做过,这次记录下来。
相关文章:
android 彩虹进度条自定义view实现
实现一个彩虹色进度条功能,不说明具体用途大家应该能猜到。想找别人造的轮子,但是没有合适的,所以决定自己实现一个。 相关知识 android 自定义view LinearGradient 线性渐变 实现步骤 自定义view 自定义一个TmcView类继承View 重写两…...
免费一年SSL证书申请——建议收藏
免费一年SSL证书申请——建议收藏 获取免费一年期SSL证书其实挺简单的 准备你的网站: 确保你的网站已经有了域名,而且这个域名已经指向你的服务器。还要检查你的服务器支持HTTPS,也就是443端口要打开,这是HTTPS默认用的。 验证域…...
【docker1】指令,docker-compose,Dockerfile
文章目录 1.pull/image,run/ps(进程),exec/commit2.save/load:docker save 镜像id,不是容器id3.docker-compose:多容器:宿主机(eth0网卡)安装docker会生成一…...
Flutter中的异步和多进程
Flutter 是一个用于创建高性能、高保真度移动应用的框架,它使用 Dart 编程语言。 在 Flutter 中,异步和多进程是两种不同的概念,用于解决不同的问题。 异步 (Asynchronous) 异步编程是一种编程范式,允许代码在等待操作完成(如网络请求、文件 I/O)时继续执行其他任务,而不…...
学习C++第二天
1.缺省参数 缺省参数的概念: 缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。 void show(int a 10) {cout << a << endl; }int main() {sho…...
解析Java中1000个常用类:AbstractSet类,你学会了吗?
推荐一个我自己写的小报童专栏导航网站: http://xbt100.top 收录了生财有术项目精选、AI海外赚钱、纯银的产品分析等专栏,陆续会收录更多的专栏,欢迎体验~复制URL可直达。 以下是正文。 在 Java 集合框架中,AbstractSet 是一个重要的抽象类,为实现自定义的集合(Set)提…...
Nginx基础概念和常用操作
文章目录 1. 安装、启动、连接2. 快速尝试部署网站3. 配置文件1. nginx.conf全局配置事件模块HTTP 模块性能优化建议 2. default.confserver 块基本设置日志设置根路径设置 4. 反向代理1. 模拟3个Web2. 链接 5. 负载均衡1. 加权轮询,Weighted Round Robin2. 最少连接…...
圈复杂度是什么?go语言调整圈复杂度举例
圈复杂度(也称为循环复杂度或McCabe复杂度)是衡量程序复杂性的一个指标,它通常与代码中的控制流结构(如条件语句、循环和函数调用)的数量相关。在Go语言中,你可以通过重构代码来降低圈复杂度,从…...
设计模式4-模版方法
设计模式 重构获得模式重构的关键技法1. 静态转动态2. 早绑定转晚绑定3. 继承转组合4. 编译时依赖转运行时依赖5. 紧耦合转松耦合 组件协助动机模式定义结构 要点总结。 例子示例解释: 重构获得模式 设计模式的目的是应对变化,提高复用 设计模式的要点…...
yii2 ActiveForm使用技巧
持续更新: 1、搜索输入框:form-inline <?php $form ActiveForm::begin([action > [index],method > get,options > [class > form-inline] (增加此行代码) ]); ?>...
【面试】基本数据类型的包装类缓存
目录 1. 说明2. Integer类分析2.1 代码块2.2 字节码2.3 分析2.4 valueOf方法 1. 说明 1.在java中,基本数据类型的包装类(Integer、Byte、Character、Short、Long、Boolean)的某些值会被缓存。2.以提高性能并减少内存使用。3.这种缓存机制是自…...
6月20日(周四)A股行情总结:A股险守3000点,恒生科技指数跌1.6%
A股三大股指走弱,科创板逆势上扬,半导体板块走强,多股20CM涨停。中芯国际港股涨超1%。恒生科技指数跌超1%。离岸人民币对美元汇率小幅走低,20日盘中最低跌至7.2874,创下2023年11月中旬以来的新低,随后收复部…...
Parallels Desktop 19 for mac破解版安装激活使用指南
Parallels Desktop 19 for Mac 乃是一款适配于 Mac 的虚拟化软件。它能让您在 Mac 计算机上同时运行多个操作系统。您可借此创建虚拟机,并于其中装设不同的操作系统,如 Windows、Linux 或 macOS。使用 Parallels Desktop 19 mac 版时,您可在 …...
JExcel API使用笔记
JExcel API使用笔记 JExcel是一个开源的支持excel的java类库,广泛利用其api来生成excel报表 API基本使用 1.创建excel文件 workbook Workbook.createWorkbook(file);//传入file文件2.创建sheet页 WritableSheet sheet workbook.createSheet("记录表&quo…...
springCloudAlibaba之分布式网关组件---gateway
gateway-网关 网关spring cloud gatewaygateway初体验gateway整合nacos简写方式 内置路由断言工厂内置断言工厂 自定义路由断言工厂自定义路由工厂 内置/自定义过滤器典型内置过滤器自定义过滤器 全局过滤器自定义全局过滤器 请求日志记录&跨域处理Gateway跨域配置…...
Springboot项目jar加密
部署的程序进行加密,防止第三方非法拷贝走项目进行二次开发或部署。我们知道java代码编译后生成的以.class结尾的字节码文件或者.jar/.war结尾的可执行文件都是可以反编译生成.java文件的,虽然反编译后生成的.java文件和原本的.java文件有些微差别&#…...
【React】高阶组件
概述 高阶组件并非一个组件,而是增强组件功能的一个函数。 高阶组件的作用是对多个组件公共逻辑进行横向抽离。 高阶组件 – React (reactjs.org) 示例 ChildCom1.jsx import React from react;function ChildCom1(props) {return (<div>这是子组件1<d…...
全面理解-Flutter(万字长文,深度解析)
1、Web 性能差,跟原生 App 存在肉眼可见的差距; 2、React Native 跟 Web 相比,支持的能力非常有限,特定长场景问题,需要三端团队一个一个处理; 3、Web 浏览器的安卓碎片化严重(感谢 X5&#x…...
RabbitMQ实战宝典:从新手到专家的全面探索
前言 在当今分布式系统架构中,消息队列已成为不可或缺的一部分,而RabbitMQ作为其中的佼佼者,凭借其强大的功能和灵活性,广泛应用于各种规模的应用场景中。本文将带你从基础概念出发,深入探讨RabbitMQ的核心特性&#…...
6月21日(周五)AH股总结:沪指失守3000点,恒生科技指数跌近2%,多只沪深300ETF午后量能显著放大
内容提要 沪指全天围绕3000点关口来回拉锯,收盘跌破3000点。白酒及光刻机概念集体走低,中芯国际港股跌超2%。CRO医药概念及水利股逆势走强。 A股低开低走 沪指全天围绕3000点关口来回拉锯,收盘跌破3000点,跌0.24%。深成指跌0.04…...
RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
黑马Mybatis
Mybatis 表现层:页面展示 业务层:逻辑处理 持久层:持久数据化保存 在这里插入图片描述 Mybatis快速入门 多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...
高防服务器能够抵御哪些网络攻击呢?
高防服务器作为一种有着高度防御能力的服务器,可以帮助网站应对分布式拒绝服务攻击,有效识别和清理一些恶意的网络流量,为用户提供安全且稳定的网络环境,那么,高防服务器一般都可以抵御哪些网络攻击呢?下面…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...
mac 安装homebrew (nvm 及git)
mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...
数据库——redis
一、Redis 介绍 1. 概述 Redis(Remote Dictionary Server)是一个开源的、高性能的内存键值数据库系统,具有以下核心特点: 内存存储架构:数据主要存储在内存中,提供微秒级的读写响应 多数据结构支持&…...
