Android自定义分段式进度条
作者:StrongDarkness 发布时间:2023-09-10 20:47:01
标签:Android,进度条
安卓自定义分段式的进度条,供大家参考,具体内容如下
前一段时间公司新项目接到一个新需求,其中界面需要用到一个分段式的进度条,找了半天没有发现类似的控件,于是决定自己写一个,话不多说,上代码
package com.djt.aienglish.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Build;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.djt.aienglish.R;
/**
* 分段式进度条
*
* @author qiu
* @date 2021/3/2 14:34
*/
public class SegmentProgressBar extends View {
/**
* 设置各种默认值
*/
private static final int DEFAULT_HEIGHT_PROGRESS_BAR = 10;
/**
* 进度条圆角
*/
private static final float mRadius = 60;
/**
* 背景色
*/
private int defaultBackgroundColor = Color.parseColor("#DDE4F4");
/**
* 进度条颜色
*/
private int defaultProgressBarColor = Color.parseColor("#3D7EFE");
/**
* 所有画图所用的画笔
*/
protected Paint mPaint = new Paint();
/**
* 进度条间距
*/
protected float mOffset = 0;
protected float mDefaultOffset = 10;
/**
* 进度条高度
*/
protected int mProgressBarHeight = dp2px(DEFAULT_HEIGHT_PROGRESS_BAR);
/**
* 除padding外的视图宽度
*/
protected float mRealWidth;
/**
* 最大值
*/
private int mMax = 100;
/**
* 当前进度
*/
private int mProgress = 0;
/**
* 分段宽度
*/
private float progressWith = 0;
public SegmentProgressBar(Context context) {
this(context, null);
}
public SegmentProgressBar(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public SegmentProgressBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initDefaultValues(context, attrs, defStyleAttr);
init();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public SegmentProgressBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initDefaultValues(context, attrs, defStyleAttr);
init();
}
/**
* 初始化布局
*
* @param context
* @param attrs
* @param defStyleAttr
*/
private void initDefaultValues(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
TypedArray arr =
context.obtainStyledAttributes(attrs, R.styleable.ProgressBar, defStyleAttr, defStyleAttr);
if (arr != null) {
mProgress = arr.getInt(R.styleable.ProgressBar_progress, 0);
mMax = arr.getInt(R.styleable.ProgressBar_max, 0);
defaultBackgroundColor = arr.getColor(R.styleable.ProgressBar_progressBackground, Color.parseColor("#DDE4F4"));
defaultProgressBarColor = arr.getColor(R.styleable.ProgressBar_progressBarColor, Color.parseColor("#3D7EFE"));
}
arr.recycle();
}
/**
* 初始化布局
*/
private void init() {
}
/**
* 最大值
*
* @param max
*/
public void setMax(int max) {
this.mMax = max;
if (max > 0) {
mOffset = mRealWidth / mMax / 8;
if (mOffset > mDefaultOffset) {
mOffset = mDefaultOffset;
}
progressWith = (mRealWidth - (mMax - 1) * mOffset) / mMax;
}
invalidate();
}
/**
* 进度值
*
* @param progress
*/
public void setProgress(int progress) {
this.mProgress = progress;
invalidate();
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
//高度
int height = measureHeight(heightMeasureSpec);
//必须调用该方法来存储View经过测量的到的宽度和高度
setMeasuredDimension(width, height);
//真正的宽度值是减去左右padding
mRealWidth = getMeasuredWidth() - getPaddingRight() - getPaddingLeft();
//使用画笔在画布上绘制进度
if (mMax > 0) {
mOffset = mRealWidth / mMax / 8;
if (mOffset > mDefaultOffset) {
mOffset = mDefaultOffset;
}
progressWith = (mRealWidth - (mMax - 1) * mOffset) / mMax;
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//真正的宽度值是减去左右padding
mRealWidth = w - getPaddingRight() - getPaddingLeft();
//使用画笔在画布上绘制进度
if (mMax > 0) {
mOffset = mRealWidth / mMax / 8;
if (mOffset > mDefaultOffset) {
mOffset = mDefaultOffset;
}
progressWith = (mRealWidth - (mMax - 1) * mOffset) / mMax;
}
invalidate();
}
/**
* EXACTLY:父控件告诉我们子控件了一个确定的大小,你就按这个大小来布局。比如我们指定了确定的dp值和macth_parent的情况。
* AT_MOST:当前控件不能超过一个固定的最大值,一般是wrap_content的情况。
* UNSPECIFIED:当前控件没有限制,要多大就有多大,这种情况很少出现。
*
* @param measureSpec
* @return 视图的高度
*/
private int measureHeight(int measureSpec) {
int result = 0;
//父布局告诉我们控件的类型
int specMode = MeasureSpec.getMode(measureSpec);
//父布局传过来的视图大小
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
result = (int) (getPaddingTop() + getPaddingBottom() + mProgressBarHeight);
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
}
return result;
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
protected synchronized void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(defaultBackgroundColor);
//设置画笔类型
mPaint.setStyle(Paint.Style.FILL);
//去除锯齿
mPaint.setAntiAlias(true);
//使用画笔在画布上绘制背景
canvas.drawRoundRect(0, 0, mRealWidth, getHeight(), mRadius, mRadius, mPaint);
//绘制进度条
mPaint.setColor(defaultProgressBarColor);
for (int i = 0; i < mProgress; i++) {
canvas.drawRoundRect(i * (progressWith + mOffset), 0, progressWith + i * (progressWith + mOffset), getHeight(), mRadius, mRadius, mPaint);
}
}
/**
* dp 2 px
*
* @param dpVal
*/
protected int dp2px(int dpVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
dpVal, getResources().getDisplayMetrics());
}
}
别忘了在value下的attr.xml加上默认属性配置
<!--分段式进度条-->
<declare-styleable name="ProgressBar">
<attr name="progress" format="integer" />
<attr name="max" format="integer" />
<attr name="progressBarColor" format="color" />
<attr name="progressBackground" format="color" />
</declare-styleable>
在布局中使用
<com.djt.aienglish.widget.SegmentProgressBar
android:id="@+id/spb"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
app:max="10"
app:progress="1" />
最后再来一个实际使用效果。
来源:https://blog.csdn.net/Strong_Darkness/article/details/115939649


猜你喜欢
- java中的方法重载和方法重写有很多区别。 下面给出了方法重载和方法覆盖之间的差异列表:编号方法重载方法重写1方法重载用于提高程序的可读性。
- 1.字符串值中包含E等科学计数法,比如12E-2,需要进行转化为普通数值0.12,2.转化函数如下: private Decima
- 一、题目描述题目实现:运行服务器程序,等待客户端程序连接。二、解题思路首先需要在服务器中建立服务器套接字,并等待客户程序的连接。创建一个类:
- 1. 最小生成树连通图中的每一棵生成树 , 都是原图的极大无环子图 , 即: 从中删去任何一条边 , 生成树就不再连通;反之 , 在其中引入
- 前言学习Java和Android将近一年的时间了,期间的成果应该就是独立完成了一个Android客户端,并且保证了其在主线版本的稳定性。期间
- 在说明映射文件规则之前,先来回顾一下ORM相关概念。1.ORM概念ORM(Object Relationship Mapping)对象关系映
- 1.底层网络接口采用apache的httpclient连接池框架; 2.图片缓存采用基于LRU的算法; 3.网络接口采用监听者模式; 4.包
- 本文实例为大家分享了java实现短信验证码5分钟有效时间,供大家参考,具体内容如下实现一个发送短信验证码的请求,要求5分钟之内重复请求,返回
- 本文实例为大家分享了java实现文件夹解压和压缩的具体代码,供大家参考,具体内容如下效果实现多个文件以及文件夹的压缩和解压代码分析impor
- gradle下载慢问题解决方法下载之后自行安装 ps:就是手动更新。官网地址和gradle各版本下载地址:官网:http://gradle.
- 一、User Agent的含义User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及
- 前言这是该工具的github地址:https://github.com/pingfangushi/screw一、引入pom.xml依赖<
- Device Administration对于这个应用,市场上很多,但是看一下评论就知道效果有多差了,因为99%一键锁屏应用没办法卸载。今天
- 本文实例为大家分享了java二叉查找树的具体代码,供大家参考,具体内容如下package 查找;import edu.princeton.c
- 前言关系复杂度一、直接插入排序基本思想:将新的数据插入已经排好的数据列中。将第一个和第二个数排序,构成有序数列然后将第三个数插进去,构成新的
- 双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很
- 范例说明Android的Widget,有许多是为了与User交互而特别设计的,但也有部分是作为程序提示、显示程序运行状态的Widget。现在
- 加密解密exe算法可能AES加密解密算法别人已经实现过,也有一些关于如何操纵自定义资源的VC代码,我只是将它们进行了组合,运用到了一起,并运
- 以下内容通过1、实现目标注入程序,2、实现主程序,3、实现注入函数,4、thumb指令集实现等4个方面详细分析了android中inline
- 先看效果图:(以公司附近的国贸为中心点)上面是地图,下面是地理位置列表,有的只有地理位置列表(QQ动态的位置),这是个很常见的功能。它有个专