自定义简单的ProgressBar
自学了Android这么长时间,一直没有怎么去接触自定义View,这段时间在一个简单的项目中需要用到一个的进度条来展示数据,于是想到了使用ProgressBar来实现,但是使用Android自带的ProgressBar样式比较难实现,于是决定自定义一个View来实现,同时也练习下自定义View的使用。写下来记录下,没怎么写过博文,格式比较乱,见谅!
这个ProgressBar是参考网上的一篇博客的代码修改而来的,因为暂时找不到原博文了,所以无法注明出处,如果有所不妥可以联系我进行删除或者注明。
下面进入正文,先展示下效果:
原博文是在中间添加了进度文字的显示,因为项目需求,我做了如下修改:
- 添加进度条圆角的设置
- 添加进度条渐变色的设定
- 添加温度的设定(
其实就是将%改为了℃) - 将文字显示改到进度条末尾
- 添加是否显示文字
具体用法如下:
android:layout_width="match_parent"android:layout_height="wrap_content"app:progress="30"//已加载进度app:progress_color="#ff3300"//已加载部分颜色(渐变色的开始色)app:progress_height="12dp"//已加载部分的高度app:background_color="#bbbbbb"//未加载部分的颜色app:background_height="2dp"//未加载部分高度app:showText="true"//是否显示文字app:progress_radius="true"//是否显示圆角app:isGradient="true"//是否显示渐变app:end_color="#ff9900"//渐变的结束色app:text_size="20sp"//文本大小app:isTemperature="true"//是否设置为温度app:maxValue="50"//最大进度
接下来讲讲我做的修改吧,其实整个过程不难,毕竟是在原有基础上进行修改的。修改过程中,主要是对绘制的位置进行了调整。
设置圆角:主要是需要注意r的设置,因为经过测试我发现,在画直线的时候,是没有将圆角的宽度计算在内的,因此要设置一个偏差值,在不设置圆角时为0,设置圆角时我们需要设置为进度条部分高度的二分之一(半圆),否则后续画线的时候为产生误差,出现已加载部分和未加载部分重叠的情况。
//直线为圆角时的偏差值int r = 0;if (isRadius) { //设置直线末端为圆角 mPaint.setStrokeCap(Paint.Cap.ROUND); //圆角的宽度 r = mProgressHeight/2;}
设置渐变:因为之前实在是没有自己尝试自定义view,因此对如何绘制渐变也是花了不少时间去谷歌,,,反省。绘制渐变的过程中主要是要确定渐变的开始位置和结束位置,其实就是已加载部分的开始位置和结束位置(注意:此时是不需要r这个偏差值的,其实很容易理解,我们设置这个偏差值是因为绘制直线没有将圆角计算在内,但是直线长度是不变的,只是直线绘制的开始位置需要加r,结束位置减r)。
//直线是否为渐变色if (isGradient){ //设置线性渐变,开始位置和结束位置于进度条相同 Shader shader = new LinearGradient(getPaddingLeft(), mHeight / 2, currentProgress, mHeight / 2,mProgressColor, endColor, Shader.TileMode.REPEAT); mPaint.setShader(shader);}
文字的位置和显示改变:文字的是否显示和是否为温度,只要是注意修改文字的宽度,在计算绘制直线的位置就好了。
文本设置:
//设置文本格式String str = mProgress + "%";//设置文本为温度if (isTemperature) str = mProgress+"℃";//获取文本宽度float textWidth = mPaint.measureText(str);//不显示文字,文本宽度为0if (!showText) textWidth = 0;
已加载部分的长度和位置计算:
float width = getMeasuredWidth() - textWidth - getPaddingLeft() - getPaddingRight() - mProgressPadding * 2 ;//当前进度应该绘制的结束位置float currentProgress = getPaddingLeft() + width * mProgress / max;
已加载部分的绘制:
//画进度条,当存在圆角时,需要考虑圆角,在画直线的时候,圆角的长度是不考虑进去的,所以在开始坐标要加上r,结束坐标要减去rcanvas.drawLine(getPaddingLeft()+r, mHeight / 2, currentProgress-r, mHeight / 2, mPaint);
未加载部分的绘制:
int y = (int) (-(mPaint.descent() + mPaint.ascent()) / 2);//设置画未加载部分的颜色和宽度mPaint.setColor(mBackgroundColor);mPaint.setStrokeWidth(mBackgroundHeight);//清除渐变mPaint.setShader(null);//画未加载部分canvas.drawLine(currentProgress , mHeight / 2, currentProgress+width*(max-mProgress)/max, mHeight / 2, mPaint);
文本的绘制:
//是否存在文字部分if (showText)canvas.drawText(str, getMeasuredWidth() - getPaddingRight()-textWidth, mHeight / 2 + y, mPaint);
修改部分基本就是这样了,整个过程,严格来说并不难,但是因为自己对自定义View部分内容的不熟悉,花费了不少时间来查资料,再次感到自己能力还是很欠缺,还需要继续学习,以后还是要尽量坚持多总结一下自己的学习吧!(写个博客好麻烦,,,这个能力也需要锻炼下啊,以后看有没有时间得去学习下Markdown)
附上github地址:https://github.com/YangX29/MyProgressBar/tree/master
最后附上完整代码:
public class MyProgress extends View { /** * 画笔 */ private Paint mPaint; /** * 默认进度值 */ private int mProgress = 0; /** * 最大值 */ private int max = 100; /** * 是否为温度 */ private boolean isTemperature = false; /** * 进度边距 */ private int mProgressPadding = dp2px(5); /** * 控件高度 */ private int mHeight = 0; /** * 字体大小 */ float mTextSize = 18f; /** * 是否显示文字 */ boolean showText = true; /** * 进度条是否为圆角 */ boolean isRadius = false; /** * 左边进度条颜色 */ int mProgressColor = Color.RED; /** * 文字颜色 */ int mTextColor = Color.RED; /** * 右边进度条颜色 */ int mBackgroundColor = Color.RED; /** * 左边进度条高度 */ int mProgressHeight = dp2px(10); /** * 右边进度条高度 */ int mBackgroundHeight = dp2px(10); /** * 是否为渐变 */ boolean isGradient = false; /** * 渐变色的结束色 * @param context */ int endColor = Color.YELLOW; public MyProgress(Context context) { this(context, null); } public MyProgress(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public MyProgress(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(attrs); } /** * 初始化 */ private void init(AttributeSet attrs) { mPaint = new Paint(); mPaint.setAntiAlias(true);//抗锯齿 mPaint.setColor(Color.RED);//画笔颜色 TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.MyProgress); //获取参数 mProgressColor = ta.getColor(R.styleable.MyProgress_progress_color, mProgressColor); mTextColor = ta.getColor(R.styleable.MyProgress_text_color, mTextColor); mBackgroundColor = ta.getColor(R.styleable.MyProgress_background_color, mBackgroundColor); mProgressHeight = (int) ta.getDimension(R.styleable.MyProgress_progress_height, mProgressHeight); mBackgroundHeight = (int) ta.getDimension(R.styleable.MyProgress_background_height, mBackgroundHeight); mTextSize = ta.getDimension(R.styleable.MyProgress_text_size, mTextSize); mProgress = ta.getInt(R.styleable.MyProgress_progress, mProgress); max = ta.getInt(R.styleable.MyProgress_maxValue, max); isTemperature = ta.getBoolean(R.styleable.MyProgress_isTemperature, isTemperature); showText = ta.getBoolean(R.styleable.MyProgress_showText, showText); isRadius = ta.getBoolean(R.styleable.MyProgress_progress_radius, isRadius); isGradient = ta.getBoolean(R.styleable.MyProgress_isGradient, isGradient); endColor = ta.getColor(R.styleable.MyProgress_end_color, endColor); ta.recycle(); mPaint.setTextSize(mTextSize);//设定文字大小,后续好测量文字高度 } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec);//得到测量模式 int widthVal = MeasureSpec.getSize(widthMeasureSpec);//默认用户需要给出明确值,所以不判断模式 int height = measureHeight(heightMeasureSpec); setMeasuredDimension(widthVal, height);//设置了测量值后,可以获取测量值。 //mRealWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight(); } /** * 测量高度 * * @param heightMeasureSpec * @return */ private int measureHeight(int heightMeasureSpec) { int result; int mode = MeasureSpec.getMode(heightMeasureSpec);//得到测量模式 int size = MeasureSpec.getSize(heightMeasureSpec); if (mode == MeasureSpec.EXACTLY) {//用户给了精确值 result = size; } else { //MeasureSpec.UNSPECIFIED MeasureSpec.AT_MOST 未指定明确参数 int textHeight = (int) (mPaint.descent() - mPaint.ascent());//得到文字高度 result = getPaddingTop() + getPaddingBottom() + Math.max(mHeight, textHeight);//高度等于进度条高度和文字高度中最高的为准,并且加上padding值 if (mode == MeasureSpec.AT_MOST) {//给定了最大值 result = Math.min(result, size); } } return result; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //获取高度 mHeight = getMeasuredHeight(); //设置文本格式 String str = mProgress + "%"; //设置文本为温度 if (isTemperature) str = mProgress+"℃"; //获取文本宽度 float textWidth = mPaint.measureText(str); //不显示文字,文本宽度为0 if (!showText) textWidth = 0; //控件宽度-文本宽度-padding=进度条总宽度,即已加载部分长度float width = getMeasuredWidth() - textWidth - getPaddingLeft() - getPaddingRight() - mProgressPadding * 2 ;//当前进度应该绘制的结束位置float currentProgress = getPaddingLeft() + width * mProgress / max; //设置进度条的颜色和高度 mPaint.setColor(mProgressColor); mPaint.setStrokeWidth(mProgressHeight); //直线为圆角时的偏差值 int r = 0; if (isRadius) { //设置直线末端为圆角 mPaint.setStrokeCap(Paint.Cap.ROUND); //圆角的宽度 r = mProgressHeight/2; } //直线是否为渐变色 if (isGradient){ //设置线性渐变,开始位置和结束位置于进度条相同 Shader shader = new LinearGradient(getPaddingLeft(), mHeight / 2, currentProgress, mHeight / 2, mProgressColor, endColor, Shader.TileMode.REPEAT); mPaint.setShader(shader); } //画进度条,当存在圆角时,需要考虑圆角,在画直线的时候,圆角的长度是不考虑进去的,所以在开始坐标要加上r,结束坐标要减去r canvas.drawLine(getPaddingLeft()+r, mHeight / 2, currentProgress-r, mHeight / 2, mPaint); int y = (int) (-(mPaint.descent() + mPaint.ascent()) / 2);// mPaint.setColor(mTextColor);// canvas.drawText(str, currentProgress + mProgressPadding, mHeight / 2 + y, mPaint); //设置画未加载部分的颜色和宽度 mPaint.setColor(mBackgroundColor); mPaint.setStrokeWidth(mBackgroundHeight); //清除渐变 mPaint.setShader(null);// canvas.drawLine(currentProgress + textWidth + mProgressPadding * 2, mHeight / 2, getMeasuredWidth() - getPaddingRight(), mHeight / 2, mPaint); //画未加载部分 canvas.drawLine(currentProgress , mHeight / 2, currentProgress+width*(max-mProgress)/max, mHeight / 2, mPaint); //设置文字颜色 mPaint.setColor(mTextColor); //是否存在文字部分 if (showText) canvas.drawText(str, getMeasuredWidth() - getPaddingRight()-textWidth, mHeight / 2 + y, mPaint); } public void setProgress(int mProgress){ this.mProgress = mProgress; invalidate(); } public int getProgress(){ return mProgress; } private int dp2px(int val) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, val, getResources().getDisplayMetrics()); } private int sp2px(int val) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, val, getResources().getDisplayMetrics()); }}
attrs文件如下:
<?xml version="1.0" encoding="utf-8"?>
更多相关文章
- Android(安卓)线程模型和 AsyncTask
- Android动态加载JAR包的实现方法
- android 重新加载网络页面设置
- Android(安卓)RecyclerView利用Glide加载大量图片into(Target)导
- android中常见的网络框架
- Android(安卓)为什么TextView文本有内容却显示为空?
- Android(安卓)EditText限制文字长度(中文算2字符,英文算1字符)
- 用vector drawable加快应用图片加载速度
- Android之Picasso