炫酷的進度條

學習資料
http://m.itdecent.cn/u/51d1fd73fb72

這里是跟隨原作者的博客進行的自定義view的學習,感謝大神的無私分享

這里盜用原作者的圖,看一下效果

進度條.gif

作為一個終極菜雞,當面對這個自定義控件的時候,其實我的內(nèi)心是拒絕的,但是冷靜下來分析一波 :

首先看一下效果,具體分析:

1.百分比提示框
2.進度條

具體分析下百分比提示框 :
分為 圓角矩形 、 下面的三角、提示文字 三部分

那么想一想我們需要準備的東西 (我這里先忽略提示文字):

畫矩形 :

畫筆 、畫筆寬度 、 矩形顏色 、 矩形的寬和高、 矩形圓角度數(shù)

畫三角 :

畫筆 、畫筆寬度 、 三角顏色 、 三角形的高 、 畫三角使用的path

畫進度框 :

進度款分為兩部分 : 背景進度 、當前進度

背景畫筆、背景顏色 、 當前進度畫筆 、當前進度顏色 、 、 當前進度值 畫筆寬度

那么接下來我們就先準備這些東西吧

  /*
    *  矩形和三角形畫筆
    * */
    Paint rectPaint;

 /*
    * 矩形、三角畫筆寬度
    * */
    private int rectPaintWidth;

 /**
     * 進度條、矩形、三角 顏色
     */
    private int progressColor = 0xFFf66b12;


 /*
    * 矩形高度
    * */
    private int rectWidth;
    private int rectHeight;

  /*
    *  準備圓角矩形  , 圓角度數(shù) ,
    * */

    RectF rectF = new RectF();

    private int roundRectRadius;


   /*
    * 畫三角形的path
    * */
    Path path = new Path();

  /*
    * 三角形高度
    * */
    private int triangleHeight;

 /*
    * 進度條背景畫筆
    * */
    Paint bgProPaint;

  /*
    * 進度條畫筆寬度
    * */

    private int progressWidth;

/**
     * 進度條背景顏色
     */
    private int bgColor = 0xFFe1e5e8;

  /*
    * 當前進度畫筆
    * */
    Paint currentProPaint;

    /**
     * 當前進度
     */
    private float currentProgress;

  /*
    * 三角與直線的margin距離
    * */
    private int marginTop;


 /*
    * 整個控件的高度寬度
    * */
    private int mViewHeight;

好了,,需要的東西差不多都準備好了, 我們就先把我們的小媳婦兒小對象們new出來,然后一些該賦值的數(shù)據(jù)也賦下值吧;

那么先來給各種寬度高度賦值吧 , dp2px()這個方法不用說了吧。

private void init() {


        progressWidth = dp2px(4); //進度條畫筆寬度 ,即進度條高度
        rectPaintWidth = dp2px(1); //矩形畫筆寬度
        rectWidth = dp2px(30);  //矩形寬度
        rectHeight = dp2px(15);//矩形高度
        triangleHeight = dp2px(3); //三角高度
        marginTop = dp2px(8); //三角與直線的距離
        roundRectRadius = dp2px(2);//圓角度數(shù)
        textPaintSize = dp2px(10); //字體大小

        //控件總共的高度   : 矩形  +  矩形畫筆高  + 三角 + margin  + 進度條;
        mViewHeight = rectHeight + triangleHeight + marginTop + progressWidth + rectPaintWidth;

    }

然后接下來,畫筆對象 , 既然要生成這么多畫筆對象, 矩形,三角,兩個進度條,那不如這些:

 /*
    *   統(tǒng)一處理畫筆
    *   畫筆寬度
    *   畫筆顏色
    *   風格
    *
    * */

    private Paint initPaint(int strokeWidth, int color, Paint.Style style) {

        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(color);  //顏色
        paint.setStyle(style);//風格
        paint.setStrokeWidth(strokeWidth); //畫筆寬度

        return paint;
    }


然后在構(gòu)造方法中,該準備的我們都準備好了

 public MyHorizontalProgressBar(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
        rectPaint = initPaint(rectPaintWidth, progressColor, Paint.Style.FILL);
        bgProPaint = initPaint(progressWidth, bgColor, Paint.Style.STROKE);
        currentProPaint = initPaint(progressWidth, progressColor, Paint.Style.STROKE);

    //    inieTextPaint();

    }

準備好了。那就畫唄 onDraw()不必多說
我們就從上到下依次畫,當然說好了,先忽略文字的
畫矩形 、畫三角 、 畫背景進度條、畫當前進度

  /*
    * 畫矩形
    * */
    private void drawRect(Canvas canvas) {
        rectF.set(0, 0, rectWidth, rectHeight);
        canvas.drawRoundRect(rectF, roundRectRadius, roundRectRadius, rectPaint);
    }
 /*
    * 畫三角
    * */
    
    private void drawTriangle(Canvas canvas) {
        
        /*
        *
        * moveTo  移動起點
        * lineTo  連接直線
        *
        * */
        path.moveTo(rectWidth / 2 - triangleHeight, rectHeight);
        path.lineTo(rectWidth / 2, rectHeight + triangleHeight);
        path.lineTo(rectWidth / 2 + triangleHeight, rectHeight);
        canvas.drawPath(path, rectPaint);    // 繪制Path 
        path.reset();

    }

 /*
        * 畫進度條背景
        *   float startX, float startY, float stopX, float stopY,
        *   @NonNull Paint paint
        *   
        *   startX   getPaddingLeft()
         *   startY   矩形高 +  三角高  +  margin 
         *   stopX    getWidth() - getPaddingRight(); 
         *   stopT   矩形高 +  三角高  +  margin
        * */
        canvas.drawLine(getPaddingLeft(), rectHeight + triangleHeight + marginTop,
                getWidth() - getPaddingRight(), rectHeight + triangleHeight + marginTop
                , bgProPaint);


        /*
        * 畫當前進度條
        * 
        * stopX   currentProgress
        * */

        canvas.drawLine(getPaddingLeft(), rectHeight + triangleHeight + marginTop, currentProgress, rectHeight + triangleHeight + marginTop,
                currentProPaint);

講波道理 ,畫到現(xiàn)在,感覺也沒什么。只要思路清晰了。還是很 easy的嘛。

先不管別的 ,該畫的都畫了,擦了。還有提示文字沒畫那 ;

那我們就畫畫文字唄,我為什么最后畫文字,因為我賊煩這個基線(baseLine),其他的全部記得了,只記得這個基線煩 ;

復習下 :

參考資料 :
http://blog.csdn.net/aigestudio/article/details/41447349

干嘣一個FontMertics, 字體測量 ,我擦。什么還不知道就特么開始量了。操蛋,好吧 ,那也先看看,F(xiàn)ontMertics定義了五個成員變量

top、ascent 、desent、bottom 、leading

首先我們要知道BaseLine ,賊煩,在Android中,文字繪制都是從BaseLine開始的;

Ascent(上坡度) 從BaseLine往上至字符最高處
Desent(下坡度) 從BaseLine往下至字符最低處
Leading (行間距) 從上一行字符的desent到該行的ascent的距離

Paint有一個唯一的子類 ,TextPaint是專門為文本繪制量身定做的筆;

好吧好吧 :我只記得了一個愛哥的計算baseLine的公式,然而我并沒有理解,有理解的大神給我講一下啊。

BaseLine
X : (畫布寬度 - 文字寬度)/2;
Y : 畫布寬度/2 - (desent + ascent)/2;

誰他么知道什么意思

那么那么 :

    private void drawText(Canvas canvas, String text) {

        int BaseX = (int) (rectWidth / 2 - textPaint.measureText(text) / 2);

        int BaseY = (int) ((rectHeight / 2) - (textPaint.ascent() + textPaint.descent()) / 2);

        canvas.drawText(text, BaseX, BaseY, textPaint);

    }


這下算是全畫完了, 接下來,也是應(yīng)該讓我們的進度條來點動畫效果了

準備個 ValueAnimator 、 準備個dur
準備你奶奶個腿 。運行了一下,發(fā)現(xiàn)哎呦我曹,,我的 wrap_content 怎么沒什么卵子用 。這不廢話 ,人那話怎么說的來

如果我們的view還需要使用wrap_content屬性,那么還必須重寫 onMeasure()方法;

   @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(measuredWidth(widthMeasureSpec), measuredHeight(heightMeasureSpec));
    }


    private int measuredWidth(int widthMeasureSpec) {
        
        
        int mode = MeasureSpec.getMode(widthMeasureSpec);
        int size = MeasureSpec.getSize(widthMeasureSpec);

        switch (mode) {
            case MeasureSpec.AT_MOST:
            case MeasureSpec.UNSPECIFIED:
                break;
            case MeasureSpec.EXACTLY:
                mWidth = size;
                break;

        }


        return mWidth;
    }


    private int measuredHeight(int heightMeasureSpec) {
        
        int mode = MeasureSpec.getMode(heightMeasureSpec);//模式
        int size = MeasureSpec.getSize(heightMeasureSpec); //大小
        
        switch (mode) {

            case MeasureSpec.EXACTLY: //精確值模式
                mHeight = size;
                break;
            case MeasureSpec.AT_MOST: //最大值模式
            case MeasureSpec.UNSPECIFIED: //  ?? 忘了
                mHeight = mViewHeight;
                break;

        }

        return mHeight;
    }

哼哼 ,,測量也測量了。這回行了吧。那接下來就真的準備下動畫吧

準備一個ValueAnimator 、準備一個動畫時間、來個延時時間看著舒服點、還帶準備什么? 先看看代碼


public void startAnimator() {

        valueAnimator = ValueAnimator.ofFloat(0, 100);
        valueAnimator.setDuration(duration);
        valueAnimator.setStartDelay(startDelay);
        valueAnimator.setInterpolator(new LinearInterpolator()); //差值器
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {

                float index = (float) animation.getAnimatedValue();

                //進度數(shù)值只顯示整數(shù),我們自己的需求,可以忽略
                text = formatNum(format2Int(index));

                currentProgress = index * mWidth / 100;


                if(index == 100){

                    if(finishLinstener != null){

                        finishLinstener.finished();

                    }

                }


                invalidate();

            }
        });

        valueAnimator.start();

    }


ValueAnimator本身不提供任何動畫效果,它更像一個數(shù)值發(fā)生器 , 我們在AnimatorUpdateListener中監(jiān)聽數(shù)值的變化,從而完成動畫的變換;

插值器
通過插值器,可以定義動畫變換速率 ,這一點非常類似物理中的加速度 ,主要作用是控制目標變量的變數(shù)值進行對應(yīng)的變化;
簡單的說,就是可以控制動畫 ,先快后慢,還是先慢后快,或者是勻速變化;

差不多了。吧。。。我曹,我忘了。圓角矩形也要跟著移動。。。其實我特么是懶得不愿動了,上來就是倆大嘴巴子。

頭一遭這么正八經(jīng)的寫,感覺寫寫真的有用,這么復習一遍,許多知識點又加深了。以后多寫寫,還是蠻好的嘛。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容