IndicateProgressBar 帶指示器的ProgressBar進度條

github地址: https://github.com/w296365959/IndicateProgressBar

同事給的效果圖索要個這樣的進度條,趁着空閒時間,就做了這個
IndicateProgressBar ,這是一個簡單的自定義View,帶指示器的進度條。
如有 不足之處,盡情指出
轉載請標明出處:
http://blog.csdn.net/w296365959/article/details/78496985

效果圖:

IndicateProgressBar

整體思路:
先把底部背景條給畫出,就是一個帶圓角的矩形;
接着我們畫進度條,我們可以看到進度條也是一個帶圓角的矩形,同理,我們一樣只要畫出一個帶圓角的矩形就可以了,只不過這個矩形長度是可以變化的而已,矩形左邊x座標爲0,右邊x座標是背景條長度*進度比例, 我們進度條顏色是隨着進度改變而漸變的,這也簡單,可以直接使用Shader 來設置漸變色。這樣進度畫好了;
接着,畫進度條的指示器,指示器室友3部分組成的,一個外框+內部填充+一個進度文本,
這都是一樣 ,畫個矩形就可以了,只不過給畫筆顏色不同,最後在畫一個文本,這文本寫在矩形框內,具體數據可以自己調試。

關鍵代碼分析:
//在ondraw裏面畫出進度條背景,進度,以及指示器

       width = getWidth() - (int) (indicateTextPaint.measureText(max + "%") + defaultMargin);//進度條最大寬度,減去文本長度+defaultMargin 是爲了放置指示器位置,
       height = getHeight();
        //畫背景
        RectF backRectF = new RectF(0, height * 2 / 5, width, height * 3 / 5);
        canvas.drawRoundRect(backRectF, radius, radius, backPaint);

        //畫進度
        RectF progressRectF = new RectF(0, height * 2 / 5, width * getScale(), height * 3 / 5);
        Shader shader = new LinearGradient(0, 0, 400, 400, startProgressColor, Color.RED, Shader.TileMode.REPEAT);//漸變
        progressPaint.setShader(shader);
        canvas.drawRoundRect(progressRectF, radius, radius, progressPaint);

        //畫指示器邊框
        float left = getScale() * width;
        float right = getScale() * width + indicateTextPaint.measureText(max + "%") + defaultMargin;

        if (left <= 0f) {//當指示器最左邊不在控件範圍時,強制左邊界=0
            left = 0f;
            right = indicateTextPaint.measureText(max + "%") + defaultMargin;
        }
        if (left >= width) {//當指示器左邊界超出控件範圍時,強制左邊界=進度最大長度
            left = width;
            right = width + indicateTextPaint.measureText(max + "%") + defaultMargin;
        }
        RectF indicatorRectF = new RectF(left, height / 5, right, height * 4 / 5);
        indicateBackPaint.setColor(textColor);
        canvas.drawRoundRect(indicatorRectF, indicatorRadius, indicatorRadius, indicateBackPaint);
        //畫指示器內部爲白色
        RectF indicatorContentRectF = new RectF(left + 2, height / 5 + 2, right - 2, height * 4 / 5 - 2);
        indicateBackPaint.setColor(Color.WHITE);
        canvas.drawRoundRect(indicatorContentRectF, indicatorRadius, indicatorRadius, indicateBackPaint);

        //畫指示器文本
        float textX = indicatorContentRectF.centerX() - indicateTextPaint.measureText(progressText) / 2;
        float textY = backRectF.centerY() + height / 9;
        canvas.drawText(progressText, textX, textY, indicateTextPaint);

然後,在onTouchEvent裏控制 手指拖動進度條,isCanTouch可以控制是否可以拖動

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (isCanTouch) {//開啓可手動拖動
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    break;
                case MotionEvent.ACTION_MOVE:
                    x = event.getX();//基於控件的座標
                /*float rawX = event.getRawX();//基於屏幕的座標
                Log.i(TAG, "x==: " + x);
                Log.i(TAG, "rawX==: " + rawX);
                Log.i(TAG, "width==: " + width);
                Log.i(TAG, "height==: " + height);*/
                    int count = (int) x * 100 / width;
                    if (count > 100) {
                        count = 100;
                    } else if (count < 0) {
                        count = 0;
                    }
                    progressText = count + "%";
                    setProgress(count);
                    Log.i(TAG, "progressText==: " + progressText);
                    invalidate();//主線程中調用刷新
                    // postInvalidate();//可在非UI線程中調用刷新,底層還是使用handler發送到主線程刷新重繪

                    break;
                case MotionEvent.ACTION_UP:
                    break;
            }

            return true;
        }else {
            return super.onTouchEvent(event);
        }
    }

代碼簡單易懂,完整代碼如下:


/**
 * Author: wangzhongming<br/>
 * Date :  2017/11/8 11:33 </br>
 * Summary: 帶指示器的進度條
 */

public class IndicateProgressBar extends View {

    private float x = 10;
    private String progressText = "0%";
    private static final String TAG = IndicateProgressBar.class.getSimpleName();
    private int width;
    private int height;

    private Paint backPaint;
    private Paint progressPaint;
    private Paint indicateTextPaint;
    private Paint indicateBackPaint;
    private int radius = 10; //進度條四個角的角度px
    private int indicatorRadius = 32; //進度指示器四個角的角度px
    private int defaultMargin = 30; //進度指示器默認多一點長度
    private int max = 100;//進度最大值
    private int progress = 0;//進度0-100
    private boolean isCanTouch = true;//進度條是否可以手動拖動
    private int startProgressColor = 0xfff29310;
    private int textColor = 0xffef4f37;
    private int gray = 0xfff5f5f5;

    public IndicateProgressBar(Context context) {
        this(context, null);
    }

    public IndicateProgressBar(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    private void initView() {
//        Android在用畫筆的時候有三種Style,分別是
//        Paint.Style.STROKE 只繪製圖形輪廓(描邊)//空心效果
//        Paint.Style.FILL 只繪製圖形內容
//        Paint.Style.FILL_AND_STROKE 既繪製輪廓也繪製內容

        //Paint.ANTI_ALIAS_FLAG 抗鋸齒
        //進度條背景畫筆
        backPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        backPaint.setColor(gray);
        backPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        //進度條進度畫筆
        progressPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        progressPaint.setStyle(Paint.Style.FILL);

        //進度條指示器框畫筆
        indicateBackPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        indicateBackPaint.setColor(textColor);
        indicateBackPaint.setTextSize(32);

        //進度條指示器文本畫筆
        indicateTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        indicateTextPaint.setColor(textColor);

    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);


        width = getWidth() - (int) (indicateTextPaint.measureText(max + "%") + defaultMargin);
        height = getHeight();
//畫背景
        RectF backRectF = new RectF(0, height * 2 / 5, width, height * 3 / 5);
        canvas.drawRoundRect(backRectF, radius, radius, backPaint);

        //畫進度
        RectF progressRectF = new RectF(0, height * 2 / 5, width * getScale(), height * 3 / 5);
        Shader shader = new LinearGradient(0, 0, 400, 400, startProgressColor, Color.RED, Shader.TileMode.REPEAT);//漸變
        progressPaint.setShader(shader);
        canvas.drawRoundRect(progressRectF, radius, radius, progressPaint);

        //畫指示器邊框
        float left = getScale() * width;
        float right = getScale() * width + indicateTextPaint.measureText(max + "%") + defaultMargin;

        if (left <= 0f) {
            left = 0f;
            right = indicateTextPaint.measureText(max + "%") + defaultMargin;
        }
        if (left >= width) {
            left = width;
            right = width + indicateTextPaint.measureText(max + "%") + defaultMargin;
        }
        RectF indicatorRectF = new RectF(left, height / 5, right, height * 4 / 5);
        indicateBackPaint.setColor(textColor);
        canvas.drawRoundRect(indicatorRectF, indicatorRadius, indicatorRadius, indicateBackPaint);
        //畫指示器內部爲白色
        RectF indicatorContentRectF = new RectF(left + 2, height / 5 + 2, right - 2, height * 4 / 5 - 2);
        indicateBackPaint.setColor(Color.WHITE);
        canvas.drawRoundRect(indicatorContentRectF, indicatorRadius, indicatorRadius, indicateBackPaint);

        //畫指示器文本
        float textX = indicatorContentRectF.centerX() - indicateTextPaint.measureText(progressText) / 2;
        float textY = backRectF.centerY() + height / 9;
        canvas.drawText(progressText, textX, textY, indicateTextPaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (isCanTouch) {//開啓可手動拖動
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    break;
                case MotionEvent.ACTION_MOVE:
                    x = event.getX();//基於控件的座標
                /*float rawX = event.getRawX();//基於屏幕的座標
                Log.i(TAG, "x==: " + x);
                Log.i(TAG, "rawX==: " + rawX);
                Log.i(TAG, "width==: " + width);
                Log.i(TAG, "height==: " + height);*/
                    int count = (int) x * 100 / width;
                    if (count > 100) {
                        count = 100;
                    } else if (count < 0) {
                        count = 0;
                    }
                    progressText = count + "%";
                    setProgress(count);
                    Log.i(TAG, "progressText==: " + progressText);
                    invalidate();//主線程中調用刷新
                    // postInvalidate();//可在非UI線程中調用刷新,底層還是使用handler發送到主線程刷新重繪

                    break;
                case MotionEvent.ACTION_UP:
                    break;
            }

            return true;
        }else {
            return super.onTouchEvent(event);
        }
    }

    /**
     * 是否開啓拖動有效
     * 默認可以手動拖動
     *
     * @param isOpen true開啓可以手動拖動
     */
    public void setCanTouch(boolean isOpen) {
        isCanTouch = isOpen;
    }


    /**
     * 設置進度,getScale()內會調用
     *
     * @param progress 0-100 ,最大進度默認100
     */
    public void setProgress(int progress) {
        this.progress = progress;
    }

    /**
     * 設置進度,getScale()內會調用
     *
     * @param progress 進度 0-100
     * @param max      最大進度 ,不寫則默認100
     */
    public void setProgress(int progress, int max) {
        this.progress = progress;
        this.max = max;
    }

    /**
     * 進度顯示百分數
     *
     * @param strText 如寫 70%
     */
    private void setProgeressText(String strText) {
        progressText = strText;
    }

    /**
     * 進度比例小數
     *
     * @return
     */
    private float getScale() {
        float scale;
        if (max == 0) {
            scale = 0;
        } else {
            scale = (float) progress / (float) max;
        }
        setProgeressText((int) (scale * 100) + "%");
        return scale;
    }


}

好了,一個簡單的帶指示器的進度條完成了!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章