自定义进度条之进阶篇

带自定义属性的进度条

image.png

前三个进度条基本是系统原生的,详情见我的上一篇文章自定义进度条之样式篇
今天我们讲一下下边的2个带文字的自定义进度条,如果对paint,canvas,bitmap.onDraw,onMeasure不太了解的同学,可以先看看自定义控件三部曲中的绘图篇

  1. 自定义属性
    在res/values下新建文件attr_progress_bar.xml

     <declare-styleable name="HorizontalProgressBarWithNumber">  // 声名属性集的名称,即这些属性是属于哪个控件的。
         <attr name="progress_unreached_color" format="color" /> //进度未达到颜色
         <attr name="progress_reached_color" format="color" />   //进度已经达到的颜色
         <attr name="progress_reached_bar_height" format="dimension" />  //进度条已经达到的高
         <attr name="progress_unreached_bar_height" format="dimension" />//进度条未达到的高
         <attr name="progress_text_size" format="dimension" />   //进度条文字的大小(SP)
         <attr name="progress_text_color" format="color" />      //进度条文字的颜色
         <attr name="progress_text_offset" format="dimension" /> //进度条文字的偏移量
         <attr name="progress_text_visibility" format="enum">    //进度条文字是否可见
             <enum name="visible" value="0" />                   //枚举值可见
             <enum name="invisible" value="1" />                 //枚举值不可见
         </attr>
     </declare-styleable>
    

.简单说一下上边所使用的 <attr name="progress_unreached_color" format="color" />

  • 其中name是我们给这个自定义属性所起的名称,
  • format是自定义属性的类型,
    Android一共给我们提供了八种自定义属性的类型,分别是:
Num format 类型
1 reference 引用
2 color 颜色
3 boolean 布尔值
4 dimension 尺寸值
5 float 浮点值
6 integer 整型值
7 string 字符串
8 enum 枚举值

2.创建自定义进度条的HorizontalProgressBarWithNumber类继承与ProgressBar

  package com.xvdong.custom.view;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.util.AttributeSet;
    import android.util.TypedValue;
    import android.widget.ProgressBar;
    
    import com.xvdong.custom.R;
    
    /**
     * Created by xvDong on 2018/5/16.
     */
    
    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
         */
        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
         */
        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);
    
            setHorizontalScrollBarEnabled(true);
    
            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();
        }
    
    
        @Override
        protected synchronized void onMeasure(int widthMeasureSpec,
                                              int heightMeasureSpec) {
            int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    
            if (heightMode != MeasureSpec.EXACTLY) {
    
                float textHeight = (mPaint.descent() + mPaint.ascent());
                int exceptHeight = (int) (getPaddingTop() + getPaddingBottom() + Math
                        .max(Math.max(mReachedProgressBarHeight,
                                mUnReachedProgressBarHeight), Math.abs(textHeight)));
    
                heightMeasureSpec = MeasureSpec.makeMeasureSpec(exceptHeight,
                        MeasureSpec.EXACTLY);
            }
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    
        }
    
        @Override
        protected synchronized void onDraw(Canvas canvas) {
            canvas.save();
            //画笔平移到指定paddingLeft, getHeight() / 2位置,注意以后坐标都为以此为0,0
            canvas.translate(getPaddingLeft(), getHeight() / 2);
    
            boolean noNeedBg = false;
            //当前进度和总值的比例
            float radio = getProgress() * 1.0f / getMax();
            //已到达的宽度
            float progressPosX = (int) (mRealWidth * radio);
            //绘制的文本
            String text = getProgress() + "%";
    
            //拿到字体的宽度和高度3265
            float textWidth = mPaint.measureText(text);
            float textHeight = (mPaint.descent() + mPaint.ascent()) / 2;
    
            //如果到达最后,则未到达的进度条不需要绘制
            if (progressPosX + textWidth > mRealWidth) {
                progressPosX = mRealWidth - textWidth;
                noNeedBg = true;
            }
    
            // 绘制已到达的进度
            float endX = progressPosX - mTextOffset / 2;
            if (endX > 0) {
                mPaint.setColor(mReachedBarColor);
                mPaint.setStrokeWidth(mReachedProgressBarHeight);
                canvas.drawLine(0, 0, endX, 0, mPaint);
            }
    
            // 绘制文本
            if (mIfDrawText) {
                mPaint.setColor(mTextColor);
                canvas.drawText(text, progressPosX, -textHeight, mPaint);
            }
    
            // 绘制未到达的进度条
            if (!noNeedBg) {
                float start = progressPosX + mTextOffset / 2 + textWidth;
                mPaint.setColor(mUnReachedBarColor);
                mPaint.setStrokeWidth(mUnReachedProgressBarHeight);
                canvas.drawLine(start, 0, mRealWidth, 0, mPaint);
            }
    
            canvas.restore();
    
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            mRealWidth = w - getPaddingRight() - getPaddingLeft();
    
        }
    
        /**
         * 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());
    
        }
    }
  1. 自定义属性在layout.xml文件中的使用
    3.1 在使用之前必须声名命名空间:
    xmlns:app="http://schemas.android.com/apk/res-auto"
    这一步一般AndroidStudio会自动帮我们声明完成.

    声明命名空间.png

    3.2 自定义属性在自定义控件上的使用:

     <com.xvdong.custom.view.HorizontalProgressBarWithNumber
         app:progress_reached_bar_height="20dp"
         app:progress_unreached_bar_height="30dp"
         app:progress_text_color="@color/colorPrimaryDark"
         app:progress_text_size="20dp"
         app:progress_reached_color="@color/colorPrimaryDark"
         app:progress_text_offset="10dp"
         app:progress_text_visibility="visible"
         app:progress_unreached_color="@color/colorAccent"
         android:padding="10dp"
         android:id="@+id/id_progressbar01"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_marginEnd="10dp"
         android:layout_marginStart="10dp"
         android:layout_marginTop="10dp"/>
    
  2. 自定义进度条的使用

         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 =  findViewById(R.id.id_progressbar01);
             mHandler.sendEmptyMessage(MSG_PROGRESS_UPDATE);
         }
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,372评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,368评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,415评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,157评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,171评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,125评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,028评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,887评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,310评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,533评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,690评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,411评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,004评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,812评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,693评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,577评论 2 353

推荐阅读更多精彩内容