炫酷的進(jìn)度條

學(xué)習(xí)資料
http://www.itdecent.cn/u/51d1fd73fb72

這里是跟隨原作者的博客進(jìn)行的自定義view的學(xué)習(xí),感謝大神的無私分享

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

進(jìn)度條.gif

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

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

1.百分比提示框
2.進(jìn)度條

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

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

畫矩形 :

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

畫三角 :

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

畫進(jìn)度框 :

進(jìn)度款分為兩部分 : 背景進(jìn)度 、當(dāng)前進(jìn)度

背景畫筆、背景顏色 、 當(dāng)前進(jìn)度畫筆 、當(dāng)前進(jìn)度顏色 、 、 當(dāng)前進(jìn)度值 畫筆寬度

那么接下來我們就先準(zhǔn)備這些東西吧

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

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

 /**
     * 進(jìn)度條、矩形、三角 顏色
     */
    private int progressColor = 0xFFf66b12;


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

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

    RectF rectF = new RectF();

    private int roundRectRadius;


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

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

 /*
    * 進(jìn)度條背景畫筆
    * */
    Paint bgProPaint;

  /*
    * 進(jìn)度條畫筆寬度
    * */

    private int progressWidth;

/**
     * 進(jìn)度條背景顏色
     */
    private int bgColor = 0xFFe1e5e8;

  /*
    * 當(dāng)前進(jìn)度畫筆
    * */
    Paint currentProPaint;

    /**
     * 當(dāng)前進(jìn)度
     */
    private float currentProgress;

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


 /*
    * 整個(gè)控件的高度寬度
    * */
    private int mViewHeight;

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

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

private void init() {


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

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

    }

然后接下來,畫筆對(duì)象 , 既然要生成這么多畫筆對(duì)象, 矩形,三角,兩個(gè)進(jìn)度條,那不如這些:

 /*
    *   統(tǒng)一處理畫筆
    *   畫筆寬度
    *   畫筆顏色
    *   風(fē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);//風(fēng)格
        paint.setStrokeWidth(strokeWidth); //畫筆寬度

        return paint;
    }


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

 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();

    }

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

  /*
    * 畫矩形
    * */
    private void drawRect(Canvas canvas) {
        rectF.set(0, 0, rectWidth, rectHeight);
        canvas.drawRoundRect(rectF, roundRectRadius, roundRectRadius, rectPaint);
    }
 /*
    * 畫三角
    * */
    
    private void drawTriangle(Canvas canvas) {
        
        /*
        *
        * moveTo  移動(dòng)起點(diǎn)
        * 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();

    }

 /*
        * 畫進(jìn)度條背景
        *   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);


        /*
        * 畫當(dāng)前進(jìn)度條
        * 
        * stopX   currentProgress
        * */

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

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

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

那我們就畫畫文字唄,我為什么最后畫文字,因?yàn)槲屹\煩這個(gè)基線(baseLine),其他的全部記得了,只記得這個(gè)基線煩 ;

復(fù)習(xí)下 :

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

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

top、ascent 、desent、bottom 、leading

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

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

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

好吧好吧 :我只記得了一個(gè)愛哥的計(jì)算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)該讓我們的進(jìn)度條來點(diǎn)動(dòng)畫效果了

準(zhǔn)備個(gè) ValueAnimator 、 準(zhǔn)備個(gè)dur
準(zhǔn)備你奶奶個(gè)腿 。運(yùn)行了一下,發(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;
    }

哼哼 ,,測(cè)量也測(cè)量了。這回行了吧。那接下來就真的準(zhǔn)備下動(dòng)畫吧

準(zhǔn)備一個(gè)ValueAnimator 、準(zhǔn)備一個(gè)動(dòng)畫時(shí)間、來個(gè)延時(shí)時(shí)間看著舒服點(diǎn)、還帶準(zhǔn)備什么? 先看看代碼


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();

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

                currentProgress = index * mWidth / 100;


                if(index == 100){

                    if(finishLinstener != null){

                        finishLinstener.finished();

                    }

                }


                invalidate();

            }
        });

        valueAnimator.start();

    }


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

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

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

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

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

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

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