欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android實(shí)現(xiàn)絢麗的自定義進(jìn)度條

 更新時(shí)間:2022年01月20日 14:15:18   作者:吐爾洪江Coding  
進(jìn)度條是在Android項(xiàng)目中很常用的組件之一,本文將為大家詳細(xì)地介紹一下自定義進(jìn)度條的實(shí)現(xiàn)過程。感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

前言

進(jìn)度條是在Android項(xiàng)目中很常用的組件之一,如果想要理解它是怎么實(shí)現(xiàn)的,首先還需要了解自定義view和Android坐標(biāo)系相關(guān)的知識(shí),下面我來詳細(xì)地介紹一下自定義進(jìn)度條的實(shí)現(xiàn)過程。

本項(xiàng)目源碼:https://gitee.com/tu_erhongjiang/android-progress-bar

效果圖

實(shí)現(xiàn)步驟

1.繪制背景圓形矩形

首先要畫出一個(gè)圓形矩形,RectF里面?zhèn)鬟f的是矩形左上角和右下角的xy坐標(biāo),這是用來確定矩形的位置和大小,然后在矩形內(nèi)部畫出一個(gè)圓形矩形。

核心代碼:canvas.drawRoundRect()

private void drawBackground(Canvas canvas){
   //圓角矩形
    RectF rectF = new RectF(padding, padding, mWidth - padding, mHeight - padding);
    canvas.drawRoundRect(rectF, round, round, mPaintRoundRect);
}

2.繪制進(jìn)度

其實(shí)里面的進(jìn)度條也是圓形矩形,只不過進(jìn)度條的畫筆是實(shí)心的。內(nèi)部進(jìn)度條矩形的大小需要略小于外面的矩形,這樣就可以實(shí)現(xiàn)上面的這種效果。如果進(jìn)度條矩形大于或等于背景矩形大小的話那就完全壓住背景中的邊框,顯示出來的只是一個(gè)沒有邊框的進(jìn)度條,所以這里需要減掉strokeWidth。

private void drawProgress(Canvas canvas){
        if (process!=0){
            RectF rectProgress = new RectF(padding + strokeWidth, padding + strokeWidth, process, mHeight - padding - strokeWidth);//內(nèi)部進(jìn)度條
            canvas.drawRoundRect(rectProgress, round, round, mPaint);
        }
    }

3.繪制文字

下面來看看怎么居中文字:

getWidth() / 2 得到的結(jié)果是中間位置的x坐標(biāo),但是從這里開始繪制文字的話不能實(shí)現(xiàn)居中的效果。所以還需要計(jì)算出文字的長度,然后把文字整體左移。mTxtWidth / 2 是文字的中心位置,也就是說文字的中心位置移到矩形的中心位置就可以實(shí)現(xiàn)居中的效果。

    private void updateText(Canvas canvas) {
        String finishedText = getResources().getString(R.string.finished);
        String defaultText = getResources().getString(R.string.defaultText);
        int percent = (int) (process / (mWidth - padding - strokeWidth) * 100);
        Paint.FontMetrics fm = mPaintText.getFontMetrics();
        int mTxtWidth = (int) mPaintText.measureText(finishedText, 0, defaultText.length());
        int mTxtHeight = (int) Math.ceil(fm.descent - fm.ascent);
        int x = getWidth() / 2 - mTxtWidth / 2; //文字在畫布中的x坐標(biāo)
        int y = getHeight() / 2 + mTxtHeight / 4; //文字在畫布中的y坐標(biāo)
        if (percent < 100) {
            canvas.drawText(percent + "%", x, y, mPaintText);
        } else {
            canvas.drawText(finishedText, x, y, mPaintText);
        }
    }

4.加入動(dòng)畫 

最后就是加入動(dòng)畫效果了,讓進(jìn)度條動(dòng)起來。我這里用到的是屬性動(dòng)畫中的valueAnimator。這種動(dòng)畫不能直接修改view,它是類似于timer,需要我們傳遞一個(gè)數(shù)值范圍和執(zhí)行時(shí)間。比如說3秒內(nèi)從1加到100。然后在接口回調(diào)時(shí)拿到當(dāng)前的進(jìn)度,執(zhí)行view的invalidate()方法,刷新UI。

 //屬性動(dòng)畫
    public void start() {
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, mWidth - padding - strokeWidth);
        valueAnimator.setDuration(duration);
        valueAnimator.setInterpolator(new DecelerateInterpolator());
        valueAnimator.addUpdateListener(animation -> {
            process = (float) animation.getAnimatedValue();
            invalidate();
        });
        valueAnimator.start();
    }

完整代碼

package com.example.floatingwindow.widget;
 
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
 
import androidx.annotation.Nullable;
 
import com.example.floatingwindow.R;
 
public class HorizontalProgressView extends View {
 
    private Paint mPaint;
    private Paint mPaintRoundRect;
    private Paint mPaintText;
    private int mWidth;
    private int mHeight;
    private int padding = 5;
    private int strokeWidth = 8;
    private int textSize = 15;
    private long duration = 3500;
    private int round;
    private float process;
 
    public HorizontalProgressView(Context context) {
        super(context);
        init();
    }
 
    public HorizontalProgressView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }
 
    public HorizontalProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }
 
    //初始化畫筆
    private void init(){
        mPaintRoundRect = new Paint();//圓角矩形
        mPaintRoundRect.setColor(getResources().getColor(R.color.back));//圓角矩形顏色
        mPaintRoundRect.setAntiAlias(true);// 抗鋸齒效果
        mPaintRoundRect.setStyle(Paint.Style.STROKE);//設(shè)置畫筆樣式
        mPaintRoundRect.setStrokeWidth(strokeWidth);//設(shè)置畫筆寬度
 
        mPaint = new Paint();
        mPaint.setColor(getResources().getColor(R.color.inner));
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mPaint.setAntiAlias(true);
        mPaint.setStrokeWidth(strokeWidth);
 
        mPaintText = new Paint();
        mPaintText.setAntiAlias(true);
        mPaintText.setStyle(Paint.Style.FILL);
        mPaintText.setColor(getResources().getColor(R.color.back));
        mPaintText.setTextSize(sp2px(textSize));
    }
 
    public void setPadding(int padding) {
        this.padding = padding;
    }
 
    public void setStrokeWidth(int strokeWidth) {
        this.strokeWidth = strokeWidth;
    }
 
    public void setTextSize(int textSize) {
        this.textSize = textSize;
    }
 
    public void setDuration(long duration) {
        this.duration = duration;
    }
 
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
        //MeasureSpec.EXACTLY,精確尺寸
        if (widthSpecMode == MeasureSpec.EXACTLY || widthSpecMode == MeasureSpec.AT_MOST) {
            mWidth = widthSpecSize;
        } else {
            mWidth = 0;
        }
        //MeasureSpec.AT_MOST,最大尺寸,只要不超過父控件允許的最大尺寸即可,MeasureSpec.UNSPECIFIED未指定尺寸
        if (heightSpecMode == MeasureSpec.AT_MOST || heightSpecMode == MeasureSpec.UNSPECIFIED) {
            mHeight = defaultHeight();
        } else {
            mHeight = heightSpecSize;
        }
        //設(shè)置控件實(shí)際大小
        round = mHeight / 2;//圓角半徑
        setMeasuredDimension(mWidth, mHeight);
    }
 
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawBackground(canvas);//繪制背景矩形
        drawProgress(canvas);//繪制進(jìn)度
        updateText(canvas);//處理文字
    }
 
    private void drawBackground(Canvas canvas){
        RectF rectF = new RectF(padding, padding, mWidth - padding, mHeight - padding);//圓角矩形
        canvas.drawRoundRect(rectF, round, round, mPaintRoundRect);
    }
 
    private void drawProgress(Canvas canvas){
        if (process!=0){
            RectF rectProgress = new RectF(padding + strokeWidth, padding + strokeWidth, process, mHeight - padding - strokeWidth);//內(nèi)部進(jìn)度條
            canvas.drawRoundRect(rectProgress, round, round, mPaint);
        }
    }
 
    private void updateText(Canvas canvas) {
        String finishedText = getResources().getString(R.string.finished);
        String defaultText = getResources().getString(R.string.defaultText);
        int percent = (int) (process / (mWidth - padding - strokeWidth) * 100);
        Paint.FontMetrics fm = mPaintText.getFontMetrics();
        int mTxtWidth = (int) mPaintText.measureText(finishedText, 0, defaultText.length());
        int mTxtHeight = (int) Math.ceil(fm.descent - fm.ascent);
        int x = getWidth() / 2 - mTxtWidth / 2; //文字在畫布中的x坐標(biāo)
        int y = getHeight() / 2 + mTxtHeight / 4; //文字在畫布中的y坐標(biāo)
        if (percent < 100) {
            canvas.drawText(percent + "%", x, y, mPaintText);
        } else {
            canvas.drawText(finishedText, x, y, mPaintText);
        }
    }
 
    //屬性動(dòng)畫
    public void start() {
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, mWidth - padding - strokeWidth);
        valueAnimator.setDuration(duration);
        valueAnimator.setInterpolator(new DecelerateInterpolator());
        valueAnimator.addUpdateListener(animation -> {
            process = (float) animation.getAnimatedValue();
            invalidate();
        });
        valueAnimator.start();
    }
 
    private int sp2px(int sp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp,
                getResources().getDisplayMetrics());
    }
 
    //進(jìn)度條默認(rèn)高度,未設(shè)置高度時(shí)使用
    private int defaultHeight() {
        float scale = getContext().getResources().getDisplayMetrics().density;
        return (int) (20 * scale + 0.5f * (20 >= 0 ? 1 : -1));
    }
 
}

以上就是橫向進(jìn)度條的實(shí)現(xiàn)步驟,整體來說還是比較簡單的,如果你對Android坐標(biāo)系和canvas比較熟悉的話自定義view實(shí)現(xiàn)起來還是很容易的。

到此這篇關(guān)于Android實(shí)現(xiàn)絢麗的自定義進(jìn)度條的文章就介紹到這了,更多相關(guān)Android自定義進(jìn)度條內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Android實(shí)現(xiàn)錄音監(jiān)聽動(dòng)畫的示例代碼

    Android實(shí)現(xiàn)錄音監(jiān)聽動(dòng)畫的示例代碼

    在很多app種內(nèi)置了語音助手,也存在各種動(dòng)畫,這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)錄音監(jiān)聽動(dòng)畫的示例代碼,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-12-12
  • 在Android中動(dòng)態(tài)添加Panel框架的實(shí)現(xiàn)代碼

    在Android中動(dòng)態(tài)添加Panel框架的實(shí)現(xiàn)代碼

    項(xiàng)目經(jīng)常會(huì)有這種需求,就是想動(dòng)態(tài)的在某個(gè)界面上添加一個(gè)Panel。比如,有一個(gè)按鈕,點(diǎn)擊后會(huì)顯示下拉菜單式的界面。這種需求,就屬于動(dòng)態(tài)添加一個(gè)Panel。需求多了,就要研究是否可以抽象出通用的框架代碼,以方便開發(fā),所以就有了以下內(nèi)容
    2013-05-05
  • 解決Android SDK下載和更新失敗的方法詳解

    解決Android SDK下載和更新失敗的方法詳解

    本篇文章是對Android SDK下載和更新失敗的解決方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • Convert WebP to PNG using java

    Convert WebP to PNG using java

    本文主要介紹Convert WebP to PNG using java,這里對 WebP 做了詳細(xì)說明,并講解Linux 環(huán)境下WebP 轉(zhuǎn)png格式的示例,有興趣的小伙伴可以參考下
    2016-08-08
  • AndroidStudio中重載方法@Override的使用詳解

    AndroidStudio中重載方法@Override的使用詳解

    這篇文章主要介紹了AndroidStudio中重載方法@Override的使用詳解,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-04-04
  • Android開發(fā)之串口編程原理和實(shí)現(xiàn)方式

    Android開發(fā)之串口編程原理和實(shí)現(xiàn)方式

    提到串口編程,就不得不提到JNI,不得不提到JavaAPI中的文件描述符類:FileDescriptor;下面我分別對JNI、FileDescriptor以及串口的一些知識(shí)點(diǎn)和實(shí)現(xiàn)的源碼進(jìn)行分析說明,感興趣的朋友可以了解下
    2013-01-01
  • Android實(shí)現(xiàn)壓縮字符串的方法示例

    Android實(shí)現(xiàn)壓縮字符串的方法示例

    最近在做Android開發(fā),遇到了需要壓縮字符串的功能,下面這篇文章主要給大家介紹了Android實(shí)現(xiàn)壓縮字符串的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面跟著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-08-08
  • 詳解Android 7.0 Settings 加載選項(xiàng)

    詳解Android 7.0 Settings 加載選項(xiàng)

    本篇文章主要介紹了Android 7.0 Settings 加載選項(xiàng),Android 7.0 Settings頂部多了一個(gè)建議選項(xiàng),多了個(gè)側(cè)邊欄,操作更加便捷了,有興趣的可以了解一下。
    2017-02-02
  • ListView的Adapter使用 之 初學(xué)ArrayAdapter String

    ListView的Adapter使用 之 初學(xué)ArrayAdapter String

    ListView是Android中經(jīng)常會(huì)使用的東西,綁定數(shù)據(jù)對于初學(xué)者來說,尤其是剛接觸編程的人來說,往往會(huì)覺得很難理解,我上大二的時(shí)候?qū)W的java,但是基本上相當(dāng)于沒有學(xué),什么都沒寫過,真正接觸編程就是開始上手學(xué)android,把這些記錄下來,自己可以回頭看下,也可以讓新手更好的理解
    2013-06-06
  • android dialog背景模糊化效果實(shí)現(xiàn)方法

    android dialog背景模糊化效果實(shí)現(xiàn)方法

    這篇文章主要為大家詳細(xì)介紹了android dialog背景模糊化效果的實(shí)現(xiàn)方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-04-04

最新評論