android自定义进度条样式,Android 自定义进度条

效果

国际惯例,效果图奉上

3d68f3156bce

在这里插入图片描述

目录

3d68f3156bce

在这里插入图片描述

前言

写在前面,由于之前其实已经写了部分自定义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上找到的例子,嗯,值得学习,感谢鸿阳大神;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值