【Android】圓形進(jìn)度條

效果圖
背景圖.png

一:分析(背景玩祟、進(jìn)度條港准、文字)

初始化需要的工具

private void init() {
        //進(jìn)度圓環(huán)
        mCirclePaint = new Paint();
        mCirclePaint.setAntiAlias(true);
        mCirclePaint.setColor(Color.parseColor(mProgressBackGround));//筆刷顏色#3BB0E2
        mCirclePaint.setStyle(Paint.Style.STROKE);
        mCirclePaint.setStrokeWidth(mCriWidth);//圓環(huán)寬度12
        mCirclePaint.setStrokeCap(Paint.Cap.ROUND);//筆刷圓角
        //文字描述
        mTitlePaint = new Paint();
        mTitlePaint.setAntiAlias(true);
        mTitlePaint.setTextSize(mHumTitleSize);//字體大小20
        mTitlePaint.setColor(Color.parseColor(mProgressBackGround));//字體顏色#3BB0E2
        mTitlePaint.setStyle(Paint.Style.STROKE);
        //背景圖,將圖片縮放到設(shè)置的寬度
        mBackgroundBitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.bg_nfc_progress), mWidth, mWidth, true);
    }

二:測(cè)量畫(huà)布寬高抄瑟,調(diào)整圓半徑凡泣、字體大小、線寬等

RxImageTool.sp2px皮假,dp2px方法百度下都有

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int specSize = MeasureSpec.getSize(widthMeasureSpec);
        // 參考寬鞋拟,處理成正方形
        setMeasuredDimension(specSize, specSize);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        // 控件寬、高
        mWidth = Math.min(h, w);
        //圓半徑
        mRadius = mWidth / 2 - mWidth / 200 * RxImageTool.dp2px(10);
        //圓寬度
        mCriWidth = mWidth / 200 * RxImageTool.sp2px(15);
        //設(shè)置字體大小
        mTitleSize = RxImageTool.sp2px(mWidth / 10);
        //設(shè)置圖片大小
        mBackgroundBitmap = Bitmap.createScaledBitmap(mBackgroundBitmap, mWidth, mWidth, true);
    }

三:繪制看看

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //圖片背景
        canvas.drawBitmap(mBackgroundBitmap, 0, 0, mTitlePaint);
        //畫(huà)圓
        drawCircle(canvas);
        //畫(huà)進(jìn)度文字
        drawTemText(canvas);
    }
 //畫(huà)圓弧
    private void drawCircle(Canvas canvas) {
        canvas.save();
        RectF rectF = new RectF(-mRadius, -mRadius, mRadius, mRadius);
        //移至畫(huà)布中心
        canvas.translate(mWidth / 2, mWidth / 2);
        //旋轉(zhuǎn)角度惹资,讓起點(diǎn)從頂部開(kāi)始
        canvas.rotate(-90);
        //畫(huà)進(jìn)度條贺纲,currentAnimationValue需根據(jù)進(jìn)度條計(jì)算
        mCirclePaint.setColor(Color.parseColor(mProgressBackGround));
        canvas.drawArc(rectF, 0,currentAnimationValue, false, mCirclePaint);
        canvas.restore();
    }

    // 畫(huà)標(biāo)題
    private void drawTemText(Canvas canvas) {
        canvas.save();
        canvas.translate(mWidth / 2, mWidth / 2);
        mTitlePaint.setTextSize(mHumTitleSize);
        mHumTitle = mProgress + "%";
        float humValue = mTitlePaint.measureText(mHumTitle);
        mTitlePaint.setColor(Color.parseColor(mProgressBackGround));
        canvas.drawText(mHumTitle, -humValue / 2, RxImageTool.dp2px(7), mTitlePaint);
    }

currentAnimationValue的計(jì)算方法

//計(jì)算1%進(jìn)度對(duì)應(yīng)的角度
mAngleOneHum = (float) 360 / (mMaxProgress - mMinProgress);
//根據(jù)當(dāng)前進(jìn)度計(jì)算需要繪制的角度
currentAnimationValue=mAngleOneHum * mProgress;

四:擴(kuò)展功能

例設(shè)置進(jìn)度、添加動(dòng)畫(huà)

//設(shè)置最大褪测、最小猴誊、進(jìn)度
    public CircleProgressView setData(int minHum, int maxHum, int progress) {
        this.mMinProgress = minHum;
        this.mMaxProgress = maxHum;
        if (progress < minHum) {
            this.mProgress = minHum;
        } else if (progress > maxHum) {
            this.mProgress = maxHum;
        } else {
            this.mProgress = progress;
        }
        mAngleOneHum = (float) 360 / (mMaxProgress - mMinProgress);
        return this;
    }

    //設(shè)置當(dāng)前進(jìn)度
    public CircleProgressView setProgress(int progress) {
        setData(mMinProgress, mMaxProgress, progress);
        currentAnimationValue=mAngleOneHum * mProgress;
        invalidate();
//        setAnimation(currentAnimationValue,mAngleOneHum * mProgress,1000);
        return this;
    }

    public int getProgress() {
        return mProgress;
    }

    /**
     * 為進(jìn)度設(shè)置動(dòng)畫(huà)
     * @param last
     * @param current
     */
    private void setAnimation(float last, float current, int duration) {
        if(progressAnim !=null&& progressAnim.isRunning()){
            progressAnim.cancel();
//            isAnimation =true;
        }
        progressAnim = ValueAnimator.ofFloat(last, current);
        progressAnim.setDuration(duration);
        progressAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                currentAnimationValue = (float) animation.getAnimatedValue();
                invalidate();
            }
        });
        progressAnim.addListener(new Animator.AnimatorListener(){

            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
//                isAnimation =false;
            }

            @Override
            public void onAnimationCancel(Animator animation) {
//                isAnimation =false;
            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        progressAnim.start();
    }

完整代碼

/**
 * urkay
 * 2020/5/12
 * 圓形進(jìn)度條
 */
public class CircleProgressView extends View {
    //控件寬
    private int mWidth = 200;
    //半徑
    private int mRadius;
    //字體寬度
    private int mTitleSize;
    // 圓環(huán)寬度
    private int mCriWidth = RxImageTool.dp2px(12);
    //文字大小
    private int mHumTitleSize = RxImageTool.sp2px(20);
    //圓筆觸
    private Paint mCirclePaint;
    //當(dāng)前進(jìn)度筆觸
    private Paint mValueCirclePaint;
    private Paint mTitlePaint;
    //圓背景色
    private String mCircleBackground = "#666666";
    //圓進(jìn)度色
    private String mProgressBackGround = "#3BB0E2";
    //最小進(jìn)度
    private int mMinProgress = 0;
    //最大進(jìn)度
    private int mMaxProgress = 100;
    //當(dāng)前進(jìn)度
    private int mProgress = 50;
    //標(biāo)題
    private String mHumTitle = "0%";
    //當(dāng)前進(jìn)度每份的角度
    private float mAngleOneHum = (float) 360 / (mMaxProgress - mMinProgress);
    private Bitmap mBackgroundBitmap;
    private ValueAnimator progressAnim;
    private float currentAnimationValue;

    public CircleProgressView(Context context) {
        super(context);
        init();
    }

    public CircleProgressView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CircleProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        //進(jìn)度圓環(huán)
        mCirclePaint = new Paint();
        mCirclePaint.setAntiAlias(true);
        mCirclePaint.setColor(Color.parseColor(mCircleBackground));
        mCirclePaint.setStyle(Paint.Style.STROKE);
        mCirclePaint.setStrokeWidth(mCriWidth);
        mCirclePaint.setStrokeCap(Paint.Cap.ROUND);//筆刷圓角
        //文字描述
        mTitlePaint = new Paint();
        mTitlePaint.setAntiAlias(true);
        mTitlePaint.setTextSize(mHumTitleSize);
        mTitlePaint.setColor(Color.parseColor(mProgressBackGround));
        mTitlePaint.setStyle(Paint.Style.STROKE);
        //背景圖
        mBackgroundBitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.bg_nfc_progress), mWidth, mWidth, true);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int specSize = MeasureSpec.getSize(widthMeasureSpec);
        // 參考寬,處理成正方形
        setMeasuredDimension(specSize, specSize);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        // 控件寬侮措、高
        mWidth = Math.min(h, w);
        //圓半徑
        mRadius = mWidth / 2 - mWidth / 200 * RxImageTool.dp2px(10);
        //圓寬度
        mCriWidth = mWidth / 200 * RxImageTool.sp2px(15);
        //設(shè)置字體大小
        mTitleSize = RxImageTool.sp2px(mWidth / 10);
        //設(shè)置圖片大小
        mBackgroundBitmap = Bitmap.createScaledBitmap(mBackgroundBitmap, mWidth, mWidth, true);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //圖片背景
        canvas.drawBitmap(mBackgroundBitmap, 0, 0, mTitlePaint);
        //畫(huà)圓
        drawCircle(canvas);
        //畫(huà)進(jìn)度文字
        drawTemText(canvas);
    }

    //畫(huà)圓弧
    private void drawCircle(Canvas canvas) {
        canvas.save();
        RectF rectF = new RectF(-mRadius, -mRadius, mRadius, mRadius);

        canvas.translate(mWidth / 2, mWidth / 2);
        canvas.rotate(-90);
        //畫(huà)背景
//        mCirclePaint.setColor(Color.parseColor(mCircleBackground));
//        canvas.drawArc(rectF, 0, 361, false, mCirclePaint);
        //畫(huà)前景
        mCirclePaint.setColor(Color.parseColor(mProgressBackGround));
        canvas.drawArc(rectF, 0,currentAnimationValue, false, mCirclePaint);
        canvas.restore();
    }

    // 畫(huà)標(biāo)題
    private void drawTemText(Canvas canvas) {
        canvas.save();
        canvas.translate(mWidth / 2, mWidth / 2);
        mTitlePaint.setTextSize(mHumTitleSize);
        mHumTitle = mProgress + "%";
        float humValue = mTitlePaint.measureText(mHumTitle);
        mTitlePaint.setColor(Color.parseColor(mProgressBackGround));
        canvas.drawText(mHumTitle, -humValue / 2, RxImageTool.dp2px(7), mTitlePaint);
    }

    //設(shè)置最大稠肘、最小、進(jìn)度
    public CircleProgressView setData(int minHum, int maxHum, int progress) {
        this.mMinProgress = minHum;
        this.mMaxProgress = maxHum;
        if (progress < minHum) {
            this.mProgress = minHum;
        } else if (progress > maxHum) {
            this.mProgress = maxHum;
        } else {
            this.mProgress = progress;
        }
        mAngleOneHum = (float) 360 / (mMaxProgress - mMinProgress);
        return this;
    }

    //設(shè)置當(dāng)前進(jìn)度
    public CircleProgressView setProgress(int progress) {
        setData(mMinProgress, mMaxProgress, progress);
        currentAnimationValue=mAngleOneHum * mProgress;
        invalidate();
//        setAnimation(currentAnimationValue,mAngleOneHum * mProgress,1000);
        return this;
    }

    public int getProgress() {
        return mProgress;
    }

    /**
     * 為進(jìn)度設(shè)置動(dòng)畫(huà)
     * @param last
     * @param current
     */
    private void setAnimation(float last, float current, int duration) {
        if(progressAnim !=null&& progressAnim.isRunning()){
            progressAnim.cancel();
//            isAnimation =true;
        }
        progressAnim = ValueAnimator.ofFloat(last, current);
        progressAnim.setDuration(duration);
        progressAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                currentAnimationValue = (float) animation.getAnimatedValue();
                invalidate();
            }
        });
        progressAnim.addListener(new Animator.AnimatorListener(){

            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
//                isAnimation =false;
            }

            @Override
            public void onAnimationCancel(Animator animation) {
//                isAnimation =false;
            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        progressAnim.start();
    }

    @Override
    protected void onAttachedToWindow() {
        setAnimation(currentAnimationValue,mAngleOneHum * mProgress,1000);
        super.onAttachedToWindow();
    }

    @Override
    protected void onDetachedFromWindow() {
        if(progressAnim !=null&& progressAnim.isRunning()){
            progressAnim.cancel();
        }
        super.onDetachedFromWindow();
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末萝毛,一起剝皮案震驚了整個(gè)濱河市项阴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌笆包,老刑警劉巖环揽,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異庵佣,居然都是意外死亡歉胶,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)巴粪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)通今,“玉大人,你說(shuō)我怎么就攤上這事肛根”杷” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵派哲,是天一觀的道長(zhǎng)臼氨。 經(jīng)常有香客問(wèn)我,道長(zhǎng)芭届,這世上最難降的妖魔是什么储矩? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任感耙,我火速辦了婚禮,結(jié)果婚禮上持隧,老公的妹妹穿的比我還像新娘即硼。我一直安慰自己,他們只是感情好屡拨,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布只酥。 她就那樣靜靜地躺著,像睡著了一般洁仗。 火紅的嫁衣襯著肌膚如雪层皱。 梳的紋絲不亂的頭發(fā)上性锭,一...
    開(kāi)封第一講書(shū)人閱讀 51,573評(píng)論 1 305
  • 那天赠潦,我揣著相機(jī)與錄音,去河邊找鬼草冈。 笑死她奥,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的怎棱。 我是一名探鬼主播哩俭,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼拳恋!你這毒婦竟也來(lái)了凡资?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤谬运,失蹤者是張志新(化名)和其女友劉穎隙赁,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體梆暖,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡伞访,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了轰驳。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片厚掷。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖级解,靈堂內(nèi)的尸體忽然破棺而出冒黑,到底是詐尸還是另有隱情,我是刑警寧澤勤哗,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布薛闪,位于F島的核電站,受9級(jí)特大地震影響俺陋,放射性物質(zhì)發(fā)生泄漏豁延。R本人自食惡果不足惜昙篙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望诱咏。 院中可真熱鬧苔可,春花似錦、人聲如沸袋狞。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)苟鸯。三九已至同蜻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間早处,已是汗流浹背湾蔓。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留砌梆,地道東北人默责。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像咸包,于是被迫代替她去往敵國(guó)和親桃序。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355