自定义进度条之进阶篇

2018-05-18  本文已影响57人  冬絮

带自定义属性的进度条

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

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);
         }
    
上一篇下一篇

猜你喜欢

热点阅读