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

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
    }


    @Override
    protected 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);
    }

    @Override
    protected 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);
    }

    @Override
    protected 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);
    }


    @Override
    protected 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.TmcView
        android: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);
    }

    @Override
    protected 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);
    }


    @Override
    protected 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;
    }

    @Override
    protected 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; // 设置一个初始位置
    }


    @Override
    protected 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;
    }

    @Override
    protected 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; // 设置一个初始位置
    }


    @Override
    protected 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中,因为只适配一种屏幕尺寸所以也没有做多尺寸适配。以前也没有做过,这次记录下来。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/735973.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

单体服务系统认证

上一节讲了如何使用JWT生成令牌&#xff0c;下面说说单体服务认证基本流程。 认证流程 流程图&#xff1a; 流程描述&#xff1a; 用户输入登录信息&#xff0c;客户端&#xff08;Web/APP等&#xff09;发起登录请求&#xff1b;服务端校验该用户是否有效&#xff0c;用户…

批量重命名神器揭秘:一键实现文件夹随机命名,自定义长度轻松搞定!

在数字化时代&#xff0c;我们经常需要管理大量的文件夹&#xff0c;尤其是对于那些需要频繁更改或整理的文件来说&#xff0c;给它们进行批量重命名可以大大提高工作效率。然而&#xff0c;传统的重命名方法既繁琐又耗时&#xff0c;无法满足高效工作的需求。今天&#xff0c;…

【05】数据模型和工作量证明-简单的区块链模型

1. 简单的区块链模型 每一个区块都保存了签一个区块的hash值,这样多个区块就可以形成一个有序的后向连接的列表。 如果,区块链中的某1区块的数据被篡改,那么该区块的hash值会被改变,那么致使由该“错误区块”引导的子链失效(不被认可),从而从结构上保证了数据的可靠性、…

视频AI分析定时任务思路解析

序言&#xff1a; 最近项目中用到视频ai分析&#xff0c;由于sdk涉及保密&#xff0c;不便透露&#xff0c;仅对定时任务分析的思路作出分享&#xff0c;仅供参考。 1、定时任务 由于ai服务器的性能上限&#xff0c;只能同时对64个rtsp流分析一种算法&#xff0c;或者对8个rts…

累了就坐下来喝杯茶 然后继续前行

前言&#xff1a; 今天是情人节就不发技术文章了 先祝愿各位有情人总成眷属。也包括我&#xff0c;哈哈哈 今天要分享的是一个diy制作的教程 因为我女朋友不在这边&#xff0c;心中那份思念难耐 所以有感而发 写了这篇diy 教程的文章 效果图&#xff1a; 需要的材料 502胶水…

动手学自然语言处理:解读大模型背后的核心技术

自从 ChatGPT 横空出世以来&#xff0c;自然语言处理&#xff08;Natural Language Processing&#xff0c;NLP&#xff09; 研究领域就出现了一种消极的声音&#xff0c;认为大模型技术导致 NLP “死了”。在某乎上就有一条热门问答&#xff0c;大家热烈地讨论了这个问题。 有…

▶《强化学习的数学原理》(2024春)_西湖大学赵世钰 Ch5 蒙特卡洛方法【model-based ——> model-free】

PPT 截取必要信息。 课程网站做习题。总体 MOOC 过一遍 1、视频 学堂在线 习题 2、 过 电子书 是否遗漏 【下载&#xff1a;本章 PDF GitHub 页面链接 】 【第二轮 才整理的&#xff0c;忘光了。。。又看了一遍视频】 3、 过 MOOC 习题 看 PDF 迷迷糊糊&#xff0c; 恍恍惚惚。…

STM32 温湿度采集与OLED显示

目录 一、I2C总线通信协议 1、I2C介绍 2、软件I2C和硬件I2C &#xff08;1&#xff09;硬件I2C &#xff08;2&#xff09;软件I2C 差异 二、AHT20温湿度传感器 接口原理介绍 1. 温度测量原理 2. 湿度测量原理 实物引脚 传感器性能 电气特性 三、任务实现 具…

工程师 - Total Phase公司介绍

Total Phase 是一家领先的嵌入式系统工具供应商&#xff0c;可简化各种通信协议的开发和调试。公司提供一系列产品&#xff0c;旨在帮助工程师和开发人员更高效地使用 I2C、SPI、USB 和 CAN 等协议。 关于Total Phase的关键信息&#xff1a; 产品&#xff1a; 协议分析仪&…

day1-web安全基础(米斯特web渗透测试)

day1-web安全基础&#xff08;米斯特web渗透测试&#xff09; 一、搭建网站二、专业术语1.域名2.木马&#xff08;1&#xff09;软件木马&#xff1a;&#xff08;2&#xff09;脚本木马&#xff1a; 3.社工4.IP5.后门6.Poc&#xff08;验证&#xff09;&#xff0c;exp&#x…

2024.06.23 刷题日记

〇、前言 今天重点刷了回溯&#xff0c;以及常见的题目。 46. 全排列 给定一个不含重复数字的数组 nums &#xff0c;返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[1,2,3],[1,3,2],[2,1,3…

提示缺少Microsoft Visual C++ 2019 Redistributable Package (x64)(下载)

下载地址&#xff1a;这个是官网下载地址&#xff1a;Microsoft Visual C 2019 Redistributable Package (x64) 步骤&#xff1a; 第一步&#xff1a;点开链接&#xff0c;找到下图所示的东西 第二步&#xff1a;点击保存下载 第三步&#xff1a;双击运行安装 第四步&#xf…

【漏洞复现】AJ-Report开源数据大屏 verification;swagger-ui RCE漏洞

0x01 产品简介 AJ-Report是一个完全开源的B平台&#xff0c;酷炫大屏展示&#xff0c;能随时随地掌控业务动态&#xff0c;让每个决策都有数据支撑。多数据源支持&#xff0c;内置mysql、elasticsearch、kudu等多种驱动&#xff0c;支持自定义数据集省去数据接口开发&#xff…

three.js 基础02 ---光源

1.光源【基础材质不受光照影响】 注&#xff1a; 除MeshBasicMaterial&#xff08;网格基础材质&#xff09;外&#xff0c;设置材质时必须同时设置光源&#xff0c;否则图形出不来 1.1 材质 漫反射 MeshBasicMaterial 高光 MeshLambertMaterial 物理 MeshStandardMa…

【数据结构】链表的大概认识及单链表的实现

目录 一、链表的概念及结构 二、链表的分类 三、单链表的实现 建立链表的节点&#xff1a; 尾插——尾删&#xff1a; 头插——头删&#xff1a; 查找&#xff1a; 指定位置之后删除——插入&#xff1a; 指定位置之前插入——删除指定位置&#xff1a; 销毁链表&am…

浏览器插件利器-allWebPluginV2.0.0.14-bata版发布

allWebPlugin简介 allWebPlugin中间件是一款为用户提供安全、可靠、便捷的浏览器插件服务的中间件产品&#xff0c;致力于将浏览器插件重新应用到所有浏览器。它将现有ActiveX插件直接嵌入浏览器&#xff0c;实现插件加载、界面显示、接口调用、事件回调等。支持谷歌、火狐等浏…

C语言中的字符输入/输出和验证输入

在C语言中&#xff0c;字符输入/输出功能允许程序与用户进行交互&#xff0c;读取用户的输入信息并展示输出结果。同时&#xff0c;验证输入的作用在于确保用户输入的数据符合预期&#xff0c;以提高程序的稳定性和可靠性&#xff0c;防止无效输入引发的错误或异常行为&#xf…

外排序(C语言实现)

前言 本篇博客讲解一下外排序&#xff0c;看这篇排序你的先去看一下&#xff1a;八大经典排序算法-CSDN博客 &#x1f493; 个人主页&#xff1a;普通young man-CSDN博客 ⏩ 文章专栏&#xff1a;排序_普通young man的博客-CSDN博客 若有问题 评论区见&#x1f4dd; &#x1f3…

二叉树的基础讲解

二叉树在遍历&#xff0c;查找&#xff0c;增删的效率上面都很高&#xff0c;是数据结构中很重要的&#xff0c;下面我们来基础的认识一下。(高级的本人还没学&#xff0c;下面的代码用伪代码或C语言写的)我会从树&#xff0c;树的一些专有名词&#xff0c;树的遍历&#xff0c…

【博客719】时序数据库基石:LSM Tree的增删查改

时序数据库基石&#xff1a;LSM Tree的增删查改 LSM结构 LSM树将任何的对数据操作都转化为对内存中的Memtable的一次插入。Memtable可以使用任意内存数据结构&#xff0c;如HashTable&#xff0c;BTree&#xff0c;SkipList等。对于有事务控制需要的存储系统&#xff0c;需要在…