Android studio实现圆形进度条

参考博客
效果图
在这里插入图片描述
MainActivity

import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Color;
import android.os.Bundle;
import android.widget.TextView;

import java.util.Timer;
import java.util.TimerTask;

public class MainActivity extends AppCompatActivity {
    private CircleProgressBar progressBar;

    private TextView percentageTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        progressBar = findViewById(R.id.progressBar);
        percentageTextView = findViewById(R.id.percentageTextView);
        // 设置最大进度值为100
     progressBar.setProgress(100);
     
        Timer timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {
            int i = 0;
            @Override
            public void run() {
                if (i <= 100) {
                    final int progress = i;
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            progressBar.setProgress(progress);
                            percentageTextView.setText("SDC" + "\n" + progress + "%" + "\n" + "充电中");
                        }
                    });
                    i++;
                } else {
                    timer.cancel();
                }
            }
        }, 0, 50);
    }
}

CircleProgressBar

import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.nfc.Tag;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import androidx.annotation.Nullable;
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;

public class CircleProgressBar extends View {

    //起始角度控制半圆开口的大小,数值越小开口越大,数值越大开口越小
    private static final float START_ANGLE = 135f;
    private static final float MAX_ANGLE = 270f;

    private float progress = 0;
    private float centerX;
    private float centerY;
    private float width;
    private float height;
    private int lineWidth = dp2px(20); // 绘制圆环的线宽
    private int pointWidth = dp2px(2); // 绘制圆点线宽

    private SweepGradient sweepGradient;
    private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);//抗锯齿标志
    private Paint pointPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private ObjectAnimator animator;

    private int[] colors = {
            Color.parseColor("#09F5E6"),
            Color.parseColor("#09F5E6"),//浅色
            Color.parseColor("#23F2A4"),
            Color.parseColor("#40EF59"),
            Color.parseColor("#7EED26"),
            Color.parseColor("#B7EC15"),
            Color.parseColor("#FFE300"),
            Color.parseColor("#FF0B00"),
            Color.parseColor("#FF0000"),//深色
    };

    public CircleProgressBar(Context context) {
        this(context, null);
    }

    public CircleProgressBar(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CircleProgressBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        paint.setColor(Color.GRAY); //设置颜色
        paint.setStyle(Paint.Style.STROKE);//设置画笔样式STROKE:描边;
        paint.setStrokeCap(Paint.Cap.ROUND);//设置圆形线帽
        paint.setStrokeWidth(lineWidth);//画笔的线宽度(lineWidth)

        pointPaint.setColor(Color.WHITE);
        pointPaint.setStyle(Paint.Style.STROKE);//点画笔的样式为描边(Paint.Style.STROKE)
        pointPaint.setStrokeWidth(pointWidth);//点画笔的线宽度(pointWidth)
    }

    public void setProgress(float progress) {
        this.progress = progress;
        invalidate();
    }
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //getWidth() 和 getHeight() 函数分别获取屏幕的宽度和高度
        width = getWidth();
        height = getHeight();

        //除以2来计算出屏幕中心点的坐标(centerX 和 centerY)
        centerX = getWidth() / 2;
        centerY = getHeight() / 2;

        //使用 SweepGradient 类创建一个扫描渐变对象,传入中心点坐标(centerX 和 centerY)、渐变颜色数组(colors)和一个可选的颜色位置数组
        sweepGradient = new SweepGradient(centerX, centerY, colors, null);
        //改变开始渐变的角度(默认从右边开始画圆渐变,旋转90度就从下方开始画圆渐变,旋转之后更好设置颜色渐变值)
        //创建一个 Matrix 对象并使用 setRotate() 方法将渐变旋转90度,以改变渐变的起始角度
        Matrix matrix = new Matrix();
        matrix.setRotate(90, centerX, centerY);

        //将渐变对象设置为画笔(paint)的着色器(shader),以实现扫描渐变效果
        sweepGradient.setLocalMatrix(matrix);
        paint.setShader(sweepGradient);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 绘制环形
        drawArc(canvas);
        // 绘制末尾圆点
        drawPoint(canvas);
    }

    private void drawArc(Canvas canvas) {
        int padding = lineWidth + pointWidth;

        canvas.drawArc(padding, padding, width - padding, height - padding, START_ANGLE, MAX_ANGLE, false, paint);
        /*
        代码作用:在指定的画布上绘制一个弧形图形,其位置和样式由参数决定
        使用画布(Canvas)对象绘制一个弧形(Arc)的图形。具体参数解释如下:
        padding:指定弧形图形的边距,即距离画布边界的距离。
        width:画布的宽度。
        height:画布的高度。
        START_ANGLE:弧形的起始角度,以度数表示。
        MAX_ANGLE:弧形的角度范围,以度数表示。
        false:指定是否使用中心点连接起始点和结束点,这里为false表示不连接。
        paint:画笔(Paint)对象,用于指定绘制弧形的样式和颜色。
         */
    }

    private void drawPoint(Canvas canvas) {
        //绘制一个圆形进度条,并在进度条上显示进度
        //创建了一个 Path 对象,然后根据给定的进度计算出扫过的角度 sweepAngle
        Path path = new Path();
        float sweepAngle = (MAX_ANGLE * progress) / 100.0f;

        Log.e("CircleProgressBar-E", "sweepAngle = " + sweepAngle + ", progress = " + progress);

        //将起始点和终止点添加到 Path 对象中,形成一个圆弧
        int padding = lineWidth + pointWidth;
        path.addArc(padding, padding, width - padding, height - padding, START_ANGLE, sweepAngle);

        //使用 PathMeasure 对象获取圆弧上指定位置的坐标,并将其存储在 pos 数组中
        PathMeasure measure = new PathMeasure(path, false);
        float[] pos = new float[2];
        //通过 pos 数组中的坐标来绘制进度条上的进度标记
        measure.getPosTan(measure.getLength() - 1, pos, null);

        pointPaint.setColor(Color.parseColor("#FF7968"));
        pointPaint.setStyle(Paint.Style.FILL);

        //在画布上绘制一个圆形。它使用了pos数组中的前两个元素作为圆心的坐标,
        //lineWidth减去pointWidth的值作为圆的半径,pointPaint作为绘制圆的画笔。绘制的圆形将会显示在画布上
        canvas.drawCircle(pos[0], pos[1], lineWidth - pointWidth, pointPaint);

        pointPaint.setColor(Color.WHITE);
        pointPaint.setStyle(Paint.Style.STROKE);
        canvas.drawCircle(pos[0], pos[1], lineWidth - pointWidth, pointPaint);
    }

    public int dp2px(final float dpValue) {
        //将设备独立像素(dp)转换为像素(px)
        //获取系统的显示度量(Resources.getSystem().getDisplayMetrics()),其中包含了设备的屏幕密度(density)信息。
        // 然后,将dpValue乘以屏幕密度(scale),再乘以0.5f,并将结果转换为整数(int)返回。
        // 这个0.5f的作用是进行四舍五入(rounding)操作,以便在转换过程中更准确地处理小数部分。
        // 最终返回的值就是dpValue对应的像素(px)值
        final float scale = Resources.getSystem().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical"
    android:background="@color/royalblue">
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_gravity="center"
        android:padding="20dp"
        android:layout_marginTop="10dp"
        android:layout_marginBottom="30dp">
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_marginRight="60dp"
        >
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="258"
        android:textColor="@color/white"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="电压(V)"
        android:textColor="@color/white"/>

    </LinearLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_marginRight="60dp">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="258"
        android:textColor="@color/white"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="电压(V)"
        android:textColor="@color/white"/>
    </LinearLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_gravity="right">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="258"
            android:textColor="@color/white"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="电压(V)"
            android:textColor="@color/white"/>

    </LinearLayout>
    </LinearLayout>
<LinearLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:layout_gravity="center">

    <com.example.halfcircleprogressbar.CircleProgressBar
        android:id="@+id/progressBar"
        android:layout_width="330dp"
        android:layout_height="330dp"
        android:layout_gravity="center"
        android:layout_centerInParent="true"
        tools:ignore="MissingClass,MissingConstraints" />

    <TextView
        android:id="@+id/percentageTextView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:layout_centerInParent="true"
        android:layout_marginTop="-150dp"
        android:textSize="24sp"
        tools:ignore="MissingConstraints"
        android:textColor="@color/white"/>

</LinearLayout>

</LinearLayout>

value/attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

 <declare-styleable name="CircleProgressView">
  //背景颜色
  <attr name="outerColor" format="color"/>
  //圆弧颜色
  <attr name="innerColor" format="color"/>
  //弧宽度
  <attr name="borderWidth" format="dimension"/>
  //渐变色起始颜色
  <attr name="foreStartColor" format="color" />
  //渐变色结束颜色
  <attr name="foreEndColor" format="color" />
 </declare-styleable>
</resources>

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

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

相关文章

rknn_toolkit以及rknpu环境搭建-rv1126

rknn_toolkit安装------------------------------------------------------------------------------- 环境要求&#xff1a;ubutu18.04 建议使用docker镜像 安装docker 参考https://zhuanlan.zhihu.com/p/143156163 镜像地址 百度企业网盘-企业云盘-企业云存储解决方案-同…

Vue3.0 新特性以及使用变更总结

Vue3.0 在2020年9月正式发布了&#xff0c;也有许多小伙伴都热情的拥抱Vue3.0。去年年底我们新项目使用Vue3.0来开发&#xff0c;这篇文章就是在使用后的一个总结&#xff0c; 包含Vue3新特性的使用以及一些用法上的变更。 图片.png 为什么要升级Vue3 使用Vue2.x的小伙伴都熟悉…

【python爬虫】4.爬虫实操(菜品爬取)

文章目录 前言项目&#xff1a;解密吴氏私厨分析过程代码实现&#xff08;一&#xff09;获取与解析提取最小父级标签一组菜名、URL、食材写循环&#xff0c;存列表 代码实现&#xff08;二&#xff09;复习总结 前言 上一关&#xff0c;我们学习了用BeautifulSoup库解析数据和…

【Linux】基础IO

目录 一、回顾C语言文件操作二、文件系统调用接口1. open2.write3.read 三、文件描述符四、重定向1.输出重定向2.输入重定向 五、dup2 一、回顾C语言文件操作 1 #include<stdio.h>2 #include<stdlib.h>3 4 #define LOG "log.txt"5 6 int main()7 {8 //…

nacos闪退等环境问题解决

nacos闪退&#xff1a;通常是jdk环境变量配置有问题&#xff0c;nacos获取不到环境变量所以闪退。因为nacos的启动文件会获取JAVA_HOME&#xff0c;如果配置的不对&#xff0c;会直接闪退。如图所示&#xff0c;nacos启动文件最开始就是获取环境变量&#xff0c;获取不到就提示…

7.Redis-list

list list常用命令lpushlrangelpushxrpushrpushxlpop / rpoplindexlinsertllenlremltrimlset 阻塞版本命令blpop/brpop 总结内部编码应用场景使用redis作为消息队列 redis中的 list 是一个双端队列, list 相当于是数组或者顺序表。list 并非是一个简单的数组&#xff0c;而是更…

宠物赛道,用AI定制宠物头像搞钱项目教程

今天给大家介绍一个非常有趣&#xff0c;而粉丝价值又极高&#xff0c;用AI去定制宠物头像或合照的AI项目。 接触过宠物行业应该知道&#xff0c;获取1位铲屎官到私域&#xff0c;这类用户的价值是极高的&#xff0c;一个宠物粉&#xff0c;是连铲个屎都要花钱的&#xff0c;每…

context.WithCancel()的使用

“ WithCancel可以将一个Context包装为cancelCtx,并提供一个取消函数,调用这个取消函数,可以Cancel对应的Context Go语言context包-cancelCtx[1] 疑问 context.WithCancel()取消机制的理解[2] 父母5s钟后出门&#xff0c;倒计时&#xff0c;父母在时要学习&#xff0c;父母一走…

计算机视觉的应用12-卷积神经网络中图像特征提取的可视化研究,让大家理解特征提取的全过程

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下计算机视觉的应用12-卷积神经网络中图像特征提取的可视化研究&#xff0c;让大家理解特征提取的全过程。 要理解卷积神经网络中图像特征提取的全过程&#xff0c;我们可以将其比喻为人脑对视觉信息的处理过程。就像…

qt day

#include "widget.h" #include "ui_widget.h" void Widget::my_slot() {} Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);this->setWindowIcon(QIcon(":/wodepeizhenshi.png"));//設置窗口的…

数据结构(Java实现)-二叉树(上)

树型结构 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。 有一个特殊的结点&#xff0c;称为根结点&…

docker高级(DockerFile解析)

1、构建三步骤 编写Dockerfile文件 docker build命令构建镜像 docker run依镜像运行容器实例 2、DockerFile构建过程解析 Dockerfile内容基础知识 1&#xff1a;每条保留字指令都必须为大写字母且后面要跟随至少一个参数 2&#xff1a;指令按照从上到下&#xff0c;顺序执行…

编程题四大算法思想(二)——回溯法:N皇后问题、子集和问题、地图填色问题、迷宫问题

文章目录 回溯法迷宫游戏 N皇后问题基本概念解空间4后问题的解空间 可行解和最优解回溯法回溯法术语回溯法的关键问题回溯法的基本思想4后问题的约束条件n后问题生成问题状态的基本方法 子集和问题一个朴素的求解方法回溯回溯法的剪枝技术 地图填色问题 回溯法 迷宫游戏 深度优…

springcloud-gateway简述

Spring Cloud Gateway 是一个用于构建 API 网关的项目&#xff0c;它是 Spring Cloud 生态系统中的一部分&#xff0c;旨在为微服务架构提供动态路由、负载均衡、安全性和监控等功能。 网关工程对应pom文件 <?xml version"1.0" encoding"UTF-8"?>…

HTTP状态码504(Gateway Timeout)报错原因分析和解决办法

文章目录 504报错原因分析一、用户角度1. 代理服务器问题2. 网络问题 二、网站管理员角度1. 服务器负载过重2. 网关配置问题3. 目标服务器响应慢4. IIS/nginx/apache服务关闭5. 维护或故障6. 数据库的慢处理也会导致504 用户角度可以采取哪些措施解决504错误1. 刷新页面2. 检查…

SQLI-labs-第一关

目录 知识点&#xff1a;单引号字符型注入 1、根据提示&#xff0c;为get注入&#xff0c;在url中输入内容​编辑 2、判断注入点 3、判断目前该表的字段数 4、判断回显位置 5、爆库名 6、爆表名 7、爆字段名 8、爆值 知识点&#xff1a;单引号字符型注入 思路&#xff1a;…

matlab使用教程(26)—常微分方程的求解

1.求解非刚性 ODE 本页包含两个使用 ode45 来求解非刚性常微分方程的示例。MATLAB 提供几个非刚性 ODE 求解器。 • ode45 • ode23 • ode78 • ode89 • ode113 对于大多数非刚性问题&#xff0c;ode45 的性能最佳。但对于允许较宽松的误差容限或刚度适中的问题&…

FI 数据源(AP) 及 增量逻辑

AP 一般AP里要分析行项目数据&#xff0c;交易数据&#xff0c;历史付款信息。 还有一些供应商主数据。 基础的抽取数据源就是下面几个&#xff1a; 0FI_AP_4: Vendors: Line Items with Delta Extrcation0FI_AP_6: Vendor Sales Figures via Delta Extraction0FI_AP_7: Ve…

小白到运维工程师自学之路 第八十集 (Jumpserver堡垒机管理)2

5、登录普通用户进行测试 这里的操作和在linux系统中的终端操作一样 在Xshell中登录 创建一个普通文件 在web终端中查看 五、审计台 在审计台中可以看到服务器的各种详细操作 在这里可以看到哪个用户在哪个时间对服务器具体使用了什么命令&#xff0c;还可以看到录频回放。 …

windows使用技巧

1、windows 快捷键 winM&#xff1a;所有页面最小化 winD&#xff1a;快速到达桌面 winE&#xff1a;打开我的电脑 winV&#xff1a;剪切板记录 win&#xff0c;&#xff1a;查看桌面&#xff08;松开恢复原样&#xff09; winW&#xff1a;全屏截屏 winR&#xff1a;快速运行…