android自定义进度条样式,Android 自定义进度条
效果
国际惯例,效果图奉上
在这里插入图片描述
目录
在这里插入图片描述
前言
写在前面,由于之前其实已经写了部分自定义View的方法,所以本来应该按照之前的系列,来进行下载暂停动画进度条,但是我把之前的圆形进度条和开始暂停动画效果合并后,出现了一点小问题,让我发现之前写的自定义View,没有使我真正的了解自定义View,那么我觉得还是有很大的问题;那么之后依旧会努力的写自定义View,初步先写静态的自定义View,之后,加上动画的自定义VIew,后续在加上相应的触摸事件,努力的把自定义VIew的方法方式全部给记录下来;努力的融汇贯通。
正文
HorizontalProgressBarWithNumber
横向的进度条;里面有详细的注释
首先继承自ProgressBar,这个是对基础的ProgressBar 进行进一步的自定义,
public class HorizontalProgressBarWithNumber extends ProgressBar{
******
}
当我们想要自定义VIew的时候,先要构思效果,那么就要设置各种属性,如下
/**
* 设置各种默认值
*/
private static final int DEFAULT_TEXT_SIZE = 10;
private static final int DEFAULT_TEXT_COLOR = 0XFFFC00D1;
private static final int DEFAULT_COLOR_UNREACHED_COLOR = 0xFFd3d6da;
private static final int DEFAULT_HEIGHT_REACHED_PROGRESS_BAR = 2;
private static final int DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR = 2;
private static final int DEFAULT_SIZE_TEXT_OFFSET = 10;
/**
* painter of all drawing things 所有画图所用的画笔
*/
protected Paint mPaint = new Paint();
/**
* color of progress number 进度号码的颜色
*/
protected int mTextColor = DEFAULT_TEXT_COLOR;
/**
* size of text (sp) 文本的大小
*/
protected int mTextSize = sp2px(DEFAULT_TEXT_SIZE);
/**
* offset of draw progress 进度条文本补偿宽度
*/
protected int mTextOffset = dp2px(DEFAULT_SIZE_TEXT_OFFSET);
/**
* height of reached progress bar 进度条高度
*/
protected int mReachedProgressBarHeight = dp2px(DEFAULT_HEIGHT_REACHED_PROGRESS_BAR);
/**
* color of reached bar 成功的文本颜色
*/
protected int mReachedBarColor = DEFAULT_TEXT_COLOR;
/**
* color of unreached bar 未完成的bar颜色
*/
protected int mUnReachedBarColor = DEFAULT_COLOR_UNREACHED_COLOR;
/**
* height of unreached progress bar 未覆盖的进度条高度
*/
protected int mUnReachedProgressBarHeight = dp2px(DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR);
/**
* view width except padding 除padding外的视图宽度
*/
protected int mRealWidth;
protected boolean mIfDrawText = true;
protected static final int VISIBLE = 0;
自定义构造函数
public HorizontalProgressBarWithNumber(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public HorizontalProgressBarWithNumber(Context context, AttributeSet attrs,
int defStyle)
{
super(context, attrs, defStyle);
obtainStyledAttributes(attrs);//初始化参数
mPaint.setTextSize(mTextSize);//文本大小
mPaint.setColor(mTextColor);//文本颜色
}
接下来就是初始化的代码:
/**
* get the styled attributes 获取属性的样式
*
* @param attrs
*/
private void obtainStyledAttributes(AttributeSet attrs)
{
// init values from custom attributes
final TypedArray attributes = getContext().obtainStyledAttributes(
attrs, R.styleable.HorizontalProgressBarWithNumber);
mTextColor = attributes
.getColor(
R.styleable.HorizontalProgressBarWithNumber_progress_text_color,
DEFAULT_TEXT_COLOR);
mTextSize = (int) attributes.getDimension(
R.styleable.HorizontalProgressBarWithNumber_progress_text_size,
mTextSize);
mReachedBarColor = attributes
.getColor(
R.styleable.HorizontalProgressBarWithNumber_progress_reached_color,
mTextColor);
mUnReachedBarColor = attributes
.getColor(
R.styleable.HorizontalProgressBarWithNumber_progress_unreached_color,
DEFAULT_COLOR_UNREACHED_COLOR);
mReachedProgressBarHeight = (int) attributes
.getDimension(
R.styleable.HorizontalProgressBarWithNumber_progress_reached_bar_height,
mReachedProgressBarHeight);
mUnReachedProgressBarHeight = (int) attributes
.getDimension(
R.styleable.HorizontalProgressBarWithNumber_progress_unreached_bar_height,
mUnReachedProgressBarHeight);
mTextOffset = (int) attributes
.getDimension(
R.styleable.HorizontalProgressBarWithNumber_progress_text_offset,
mTextOffset);
int textVisible = attributes
.getInt(R.styleable.HorizontalProgressBarWithNumber_progress_text_visibility,
VISIBLE);
if (textVisible != VISIBLE)
{
mIfDrawText = false;
}
attributes.recycle();
}
上面当中的参数和属性都在attr.xml中声明的,如下
接下来,我们要重写onMeasure方法,在其中获取父控件传递过来的参数
protected synchronized void onMeasure(int widthMeasureSpec,
int heightMeasureSpec)
{
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = measureHeight(heightMeasureSpec);//高度
setMeasuredDimension(width, height);//必须调用该方法来存储View经过测量的到的宽度和高度
mRealWidth = getMeasuredWidth() - getPaddingRight() - getPaddingLeft();//真正的宽度值是减去左右padding
}
其中measureHeight() 方法是获取视图的高度,视图的样式中拥有进度条和文本,要判断文本的高度和进度条的高度;
/**
* 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
{
/**
* mPaint.descent() 最高点的高度
* mPaint.ascent() 最低点的高度
*/
float textHeight = (mPaint.descent() - mPaint.ascent());// 设置文本的高度
/**
* Math.abs() 返回绝对值
* Math.max 返回最大值
* Math.min 返回最小值
*/
result = (int) (getPaddingTop() + getPaddingBottom() + Math.max(
Math.max(mReachedProgressBarHeight,
mUnReachedProgressBarHeight), Math.abs(textHeight)));
if (specMode == MeasureSpec.AT_MOST)
{
result = Math.min(result, specSize);
}
}
return result;
}
以上全部完成后,就可以开始onDraw()方法了;
/**
* 开始画
*/
@Override
protected synchronized void onDraw(Canvas canvas)
{
canvas.save();
/**
* 设置偏移后的坐标原点 以原来为基础上偏移后, 例如: (100,100), translate(1,1), 坐标原点(101,101);
*/
canvas.translate(getPaddingLeft(), getHeight() / 2);
boolean noNeedBg = false;
float radio = getProgress() * 1.0f / getMax();//设置进度
float progressPosX = (int) (mRealWidth * radio);//设置当前进度的宽度
String text = getProgress() + "%";//设置文本
// mPaint.getTextBounds(text, 0, text.length(), mTextBound);
float textWidth = mPaint.measureText(text);//返回文本的宽度
float textHeight = (mPaint.descent() + mPaint.ascent()) / 2;//设置文本的高度
if (progressPosX + textWidth > mRealWidth)
{//当文本和当前进度的宽度大于bar的宽度时
progressPosX = mRealWidth - textWidth;
noNeedBg = true;
}
// draw reached bar 画出bar
float endX = progressPosX - mTextOffset / 2;//绘制已到达的进度
if (endX > 0)
{//绘制已到达的进度
mPaint.setColor(mReachedBarColor);
mPaint.setStrokeWidth(mReachedProgressBarHeight);
canvas.drawLine(0, 0, endX, 0, mPaint);
}
// draw progress bar
// measure text bound
if (mIfDrawText)
{//绘制文本
mPaint.setColor(mTextColor);
canvas.drawText(text, progressPosX, -textHeight, mPaint);
}
// draw unreached bar
if (!noNeedBg)
{//绘制未到达的进度条
float start = progressPosX + mTextOffset / 2 + textWidth;
mPaint.setColor(mUnReachedBarColor);
mPaint.setStrokeWidth(mUnReachedProgressBarHeight);
canvas.drawLine(start, 0, mRealWidth, 0, mPaint);
}
canvas.restore();
}
在分享两个转换的方法
/**
* dp 2 px
*
* @param dpVal
*/
protected int dp2px(int dpVal)
{
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
dpVal, getResources().getDisplayMetrics());
}
/**
* sp 2 px
*
* @param spVal
* @return
*/
protected int sp2px(int spVal)
{
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
spVal, getResources().getDisplayMetrics());
}
最后自定义View 全部实现,奉上全部代码
public class HorizontalProgressBarWithNumber extends ProgressBar
{
/**
* 设置各种默认值
*/
private static final int DEFAULT_TEXT_SIZE = 10;
private static final int DEFAULT_TEXT_COLOR = 0XFFFC00D1;
private static final int DEFAULT_COLOR_UNREACHED_COLOR = 0xFFd3d6da;
private static final int DEFAULT_HEIGHT_REACHED_PROGRESS_BAR = 2;
private static final int DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR = 2;
private static final int DEFAULT_SIZE_TEXT_OFFSET = 10;
/**
* painter of all drawing things 所有画图所用的画笔
*/
protected Paint mPaint = new Paint();
/**
* color of progress number 进度号码的颜色
*/
protected int mTextColor = DEFAULT_TEXT_COLOR;
/**
* size of text (sp) 文本的大小
*/
protected int mTextSize = sp2px(DEFAULT_TEXT_SIZE);
/**
* offset of draw progress 进度条文本补偿宽度
*/
protected int mTextOffset = dp2px(DEFAULT_SIZE_TEXT_OFFSET);
/**
* height of reached progress bar 进度条高度
*/
protected int mReachedProgressBarHeight = dp2px(DEFAULT_HEIGHT_REACHED_PROGRESS_BAR);
/**
* color of reached bar 成功的文本颜色
*/
protected int mReachedBarColor = DEFAULT_TEXT_COLOR;
/**
* color of unreached bar 未完成的bar颜色
*/
protected int mUnReachedBarColor = DEFAULT_COLOR_UNREACHED_COLOR;
/**
* height of unreached progress bar 未覆盖的进度条高度
*/
protected int mUnReachedProgressBarHeight = dp2px(DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR);
/**
* view width except padding 除padding外的视图宽度
*/
protected int mRealWidth;
protected boolean mIfDrawText = true;
protected static final int VISIBLE = 0;
public HorizontalProgressBarWithNumber(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public HorizontalProgressBarWithNumber(Context context, AttributeSet attrs,
int defStyle)
{
super(context, attrs, defStyle);
obtainStyledAttributes(attrs);//初始化参数
mPaint.setTextSize(mTextSize);//文本大小
mPaint.setColor(mTextColor);//文本颜色
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec,
int heightMeasureSpec)
{
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = measureHeight(heightMeasureSpec);//高度
setMeasuredDimension(width, height);//必须调用该方法来存储View经过测量的到的宽度和高度
mRealWidth = getMeasuredWidth() - getPaddingRight() - getPaddingLeft();//真正的宽度值是减去左右padding
}
/**
* 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
{
/**
* mPaint.descent() 最高点的高度
* mPaint.ascent() 最低点的高度
*/
float textHeight = (mPaint.descent() - mPaint.ascent());// 设置文本的高度
/**
* Math.abs() 返回绝对值
* Math.max 返回最大值
* Math.min 返回最小值
*/
result = (int) (getPaddingTop() + getPaddingBottom() + Math.max(
Math.max(mReachedProgressBarHeight,
mUnReachedProgressBarHeight), Math.abs(textHeight)));
if (specMode == MeasureSpec.AT_MOST)
{
result = Math.min(result, specSize);
}
}
return result;
}
/**
* get the styled attributes 获取属性的样式
*
* @param attrs
*/
private void obtainStyledAttributes(AttributeSet attrs)
{
// init values from custom attributes
final TypedArray attributes = getContext().obtainStyledAttributes(
attrs, R.styleable.HorizontalProgressBarWithNumber);
mTextColor = attributes
.getColor(
R.styleable.HorizontalProgressBarWithNumber_progress_text_color,
DEFAULT_TEXT_COLOR);
mTextSize = (int) attributes.getDimension(
R.styleable.HorizontalProgressBarWithNumber_progress_text_size,
mTextSize);
mReachedBarColor = attributes
.getColor(
R.styleable.HorizontalProgressBarWithNumber_progress_reached_color,
mTextColor);
mUnReachedBarColor = attributes
.getColor(
R.styleable.HorizontalProgressBarWithNumber_progress_unreached_color,
DEFAULT_COLOR_UNREACHED_COLOR);
mReachedProgressBarHeight = (int) attributes
.getDimension(
R.styleable.HorizontalProgressBarWithNumber_progress_reached_bar_height,
mReachedProgressBarHeight);
mUnReachedProgressBarHeight = (int) attributes
.getDimension(
R.styleable.HorizontalProgressBarWithNumber_progress_unreached_bar_height,
mUnReachedProgressBarHeight);
mTextOffset = (int) attributes
.getDimension(
R.styleable.HorizontalProgressBarWithNumber_progress_text_offset,
mTextOffset);
int textVisible = attributes
.getInt(R.styleable.HorizontalProgressBarWithNumber_progress_text_visibility,
VISIBLE);
if (textVisible != VISIBLE)
{
mIfDrawText = false;
}
attributes.recycle();
}
/**
* 开始画
*/
@Override
protected synchronized void onDraw(Canvas canvas)
{
canvas.save();
/**
* 设置偏移后的坐标原点 以原来为基础上偏移后, 例如: (100,100), translate(1,1), 坐标原点(101,101);
*/
canvas.translate(getPaddingLeft(), getHeight() / 2);
boolean noNeedBg = false;
float radio = getProgress() * 1.0f / getMax();//设置进度
float progressPosX = (int) (mRealWidth * radio);//设置当前进度的宽度
String text = getProgress() + "%";//设置文本
// mPaint.getTextBounds(text, 0, text.length(), mTextBound);
float textWidth = mPaint.measureText(text);//返回文本的宽度
float textHeight = (mPaint.descent() + mPaint.ascent()) / 2;//设置文本的高度
if (progressPosX + textWidth > mRealWidth)
{//当文本和当前进度的宽度大于bar的宽度时
progressPosX = mRealWidth - textWidth;
noNeedBg = true;
}
// draw reached bar 画出bar
float endX = progressPosX - mTextOffset / 2;//设置文本补偿宽度
if (endX > 0)
{
mPaint.setColor(mReachedBarColor);
mPaint.setStrokeWidth(mReachedProgressBarHeight);
canvas.drawLine(0, 0, endX, 0, mPaint);
}
// draw progress bar
// measure text bound
if (mIfDrawText)
{
mPaint.setColor(mTextColor);
canvas.drawText(text, progressPosX, -textHeight, mPaint);
}
// draw unreached bar
if (!noNeedBg)
{
float start = progressPosX + mTextOffset / 2 + textWidth;
mPaint.setColor(mUnReachedBarColor);
mPaint.setStrokeWidth(mUnReachedProgressBarHeight);
canvas.drawLine(start, 0, mRealWidth, 0, mPaint);
}
canvas.restore();
}
/**
* dp 2 px
*
* @param dpVal
*/
protected int dp2px(int dpVal)
{
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
dpVal, getResources().getDisplayMetrics());
}
/**
* sp 2 px
*
* @param spVal
* @return
*/
protected int sp2px(int spVal)
{
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
spVal, getResources().getDisplayMetrics());
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mRealWidth = w - getPaddingRight() - getPaddingLeft();
}
}
实现
xml界面
xmlns:tools="http://schemas.android.com/tools"
xmlns:zhy="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent" >
android:id="@+id/id_progressbar01"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_marginTop="50dip"
android:padding="5dp" />
mainActivity() 实现
public class MainActivity extends Activity {
private HorizontalProgressBarWithNumber mProgressBar;
private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
int progress = mProgressBar.getProgress();
mProgressBar.setProgress(++progress);
if (progress >= 100) {
mHandler.removeMessages(MSG_PROGRESS_UPDATE);
}
mHandler.sendEmptyMessageDelayed(MSG_PROGRESS_UPDATE, 100);
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mProgressBar = (HorizontalProgressBarWithNumber) findViewById(R.id.id_progressbar01);
mHandler.sendEmptyMessage(MSG_PROGRESS_UPDATE);
}
以上就是全部功能的实现了
总结
自定义View
先构思效果
根据效果 , 声明配置相应参数
想好怎么计算View的宽度和高度
如果画出来
开始做吧
感谢
这个是从鸿阳大神的Github上找到的例子,嗯,值得学习,感谢鸿阳大神;
android自定义进度条样式,Android 自定义进度条相关推荐
- android自定义漂亮按钮样式,Android开发之漂亮Button样式
开发中各种样式的Button,其实这些样式所有的View都可以共用的,可能对于你改变的只有颜色 所有的都是用代码实现 150CC48D90067F05BFAC966F4EE3E21D.jpg 边框样式 ...
- android的checkbox设置样式,android自定义checkBox的样式
释放双眼,带上耳机,听听看~! 今天,随便讲讲自定义CheckBox的样式. 第一种方法: 1.在drawable文件新建checkbox_style.xml. 2.定义一个style,使用上面的xm ...
- android自定义进度条样式,android 进度条ProgressBar样式设置
普通圆形ProgressBar 该类型进度条也就是一个表示运转的过程,例如发送短信,连接网络等等,表示一个过程正在执行中.一般只要在XML布局中定义就可以了. android:layout_width ...
- AndroidStudio安卓原生开发_UI高级_自定义主题和样式---Android原生开发工作笔记129
然后我们再来看android中的主题和样式,首先我们去看主题, 主题就是我们看到的一个app的整体样式.但是他可以设置给某个activity,所以也可以具体点说, 他是activity窗体级别的. 而 ...
- android 自定义edittext方框样式,Android之EditText自定义边框和边框颜色(转载)
介绍一种比较常见的用法 第一步:准备两张图片大小一样,颜色不同的图片.图片名称分为:editbox_focus.png和editbox_normal.png 放入工程的drawable文件夹下. 第二 ...
- Android系统自带样式(@android:style/)
在AndroidManifest.xml文件的activity中配置 (API 18中Manifest文件中,<activity />要有android:theme="@an ...
- android 动态改变button样式,Android 修改button颜色
之前觉得button颜色修改,直接修改background就行了,但是会引发一系列的问题.比如原来的波纹效果没有了,button的状态改变的时候(例如,被禁用了),button的颜色没有任何变化. 这 ...
- android圆形的按钮样式,android – 如何绘制一个完美的圆形按钮?
我想绘制一个完美的圆形按钮. 我尝试使用以下代码: android:shape="oval" > android:width="3dip" android ...
- android流程化步骤样式,Android RecyclerView 解析之绘制流程篇
前言: 当前市场上有很多成熟的RecyclerView分析文章,但那始终是其他人总结出来的,还得自己动手分析,才知道自己理解了有多少,当然这个也算是加深对RecyclerView对理解吧: 官方简介: ...
最新文章
- java通过System.getProperty获取系统属性
- Linux程序开机启动
- java开发环境安装原理,java开发环境搭建 java开发环境的完整搭建过程
- 如何学习前端开发,有哪些前端教程,前端学习路线图?
- 如何制作扫描版的文档
- C++ 判断字符串是否全是数字
- 关于constexpr
- 【Visual c++ Build Tools】下载
- 二、设计模式总览及工厂模式详解
- 最大堆(创建、删除、插入和堆排序)图文详解
- java-net-php-python-64jspm自主学习试题库系统录像演示2019查重计算机毕业设计程序
- ISP算法----AWB总结及源代码
- 数仓工具—Hive源码之SQL解析Antlr入门(7)
- 自然语言处理(NLP)的一般处理流程!
- python能打包成apk吗_超详细APK打包教程
- 字节女测试工程师万字总结的软件测试入门技巧
- html5立体照片墙效果,HTML5特效可以 14种jQuery超酷3D网格照片墙动画特效源码
- 【教学类-29-02】20230402《门牌号-黏贴版打印数量调查教学实践(6层*5间)》-(中班《我爱我家》偏数学)
- 关于Lotus Notes限制Domino邮箱超出限额的用户收发邮件
- Windows10必做的优化