自学了Android这么长时间,一直没有怎么去接触自定义View,这段时间在一个简单的项目中需要用到一个的进度条来展示数据,于是想到了使用ProgressBar来实现,但是使用Android自带的ProgressBar样式比较难实现,于是决定自定义一个View来实现,同时也练习下自定义View的使用。写下来记录下,没怎么写过博文,格式比较乱,见谅!

这个ProgressBar是参考网上的一篇博客的代码修改而来的,因为暂时找不到原博文了,所以无法注明出处,如果有所不妥可以联系我进行删除或者注明。

下面进入正文,先展示下效果:

原博文是在中间添加了进度文字的显示,因为项目需求,我做了如下修改:

  1. 添加进度条圆角的设置
  2. 添加进度条渐变色的设定
  3. 添加温度的设定(其实就是将%改为了℃
  4. 将文字显示改到进度条末尾
  5. 添加是否显示文字

具体用法如下:

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"?>                                                                                                                                

 

更多相关文章

  1. Android(安卓)线程模型和 AsyncTask
  2. Android动态加载JAR包的实现方法
  3. android 重新加载网络页面设置
  4. Android(安卓)RecyclerView利用Glide加载大量图片into(Target)导
  5. android中常见的网络框架
  6. Android(安卓)为什么TextView文本有内容却显示为空?
  7. Android(安卓)EditText限制文字长度(中文算2字符,英文算1字符)
  8. 用vector drawable加快应用图片加载速度
  9. Android之Picasso

随机推荐

  1. Android中进程间通信(IPC)方式总结
  2. Android(安卓)Watchdog(看门狗)分析
  3. 优雅的构建 Android(安卓)项目之磁盘缓存
  4. Android中Activity生命周期说明及使用
  5. android开发过程Debug包签名问题
  6. java/android 设计模式学习笔记(18)---中介
  7. 【Android】日期拾取器、时间拾取器与菜
  8. 一个Android小白的学习经验
  9. [置顶] android 从资源中获取数组
  10. 第3.2.2节 抽象布局与抽象样式