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

Android自定義view實現(xiàn)多色進度條GradientProgressView的繪制

 更新時間:2023年08月13日 14:08:22   作者:人間正四月  
我們常使用shape實現(xiàn)漸變色,但是shape的極限卻只有三色,如果有超過三種顏色的View的要求,那么我們就不得不去自定義View來實現(xiàn)這個需求,所以下面我們就來看看如何自定義view實現(xiàn)多色進度條的繪制吧

前言

我們常使用shape實現(xiàn)漸變色,但是shape的極限卻只有三色,如果有超過三種顏色的View的要求,那么我們就不得不去自定義View來實現(xiàn)這個需求。不過它的難度也是很低的,實現(xiàn)起來很輕松。接下來我分析一下我的思路。 先上圖:

一、GradientProgressView準備工作

  • color:漸變進度條的多種顏色
  • 圖形:如果是圓柱形就使用RectF,矩形就用Rect,一個用于顯示原色進度,一個用于顯示漸變進度條
  • 漸變?nèi)旧鳎篖inearGradient
  • 寬高:mHeight、mWidth
  • 圓柱的半徑:mRadius 屬性代碼如下
    private int colorStart; // 顏色:進度1
    private int colorEnd; // 顏色:進度5
    private int colorStart2;// 顏色:進度2
    private int colorEnd0;// 顏色:進度4
    private int colorCenter;// 顏色:進度3
    private Paint mGradientPaint;// 漸變畫筆
    private Paint mPaint;// 默認畫筆
    private RectF mBackGroundRect; // 原色圖形
    private RectF mGradientRect;// 染色圖形
    private LinearGradient backGradient;// 漸變色
    private int mHeight;
    private int mWidth;
    private int mRadius;

二、繪制

1.初始化屬性

因為這個自定義View只為了滿足公司需求,所有我并未將其的功能擴展開來,所有沒有自定義屬性,都是寫死在代碼中,后續(xù)有空再優(yōu)化。 主要三步驟:初始化顏色,初始化畫筆,初始化圖形。 最好先寫死需要的寬高,避免在使用的使用還未測量就進行繪制

    private void init(Context context, @Nullable AttributeSet attrs){
        // 初始化畫筆
        mGradientPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        colorStart = Color.parseColor("#63DC80");
        colorStart2 = Color.parseColor("#A8DB5B");
        colorCenter = Color.parseColor("#FFCE48");
        colorEnd0 = Color.parseColor("#FE7B39");
        colorEnd = Color.parseColor("#E8402B");
        mPaint.setColor(Color.parseColor("#EDEDED"));
        if (attrs!=null){
        }
        //設(shè)置抗鋸齒
        mGradientPaint.setAntiAlias(true);
        //設(shè)置防抖動
        mGradientPaint.setDither(true);
        mGradientPaint.setStyle(Paint.Style.FILL);
        //設(shè)置抗鋸齒
        mPaint.setAntiAlias(true);
        //設(shè)置防抖動
        mPaint.setDither(true);
        mPaint.setStyle(Paint.Style.FILL);
        mBackGroundRect = new RectF();
        // 防止渲染還未完成就顯示,使得寬高還未測量。先在初始化這里定義好跟xml中相同的寬高
        mWidth = (int) (Resources.getSystem().getDisplayMetrics().widthPixels-context.getResources().getDimension(R.dimen.base_dp_56));
        mHeight = (int) (context.getResources().getDimension(R.dimen.base_dp_8));
    }

2.測量寬高

這一步一般來說已經(jīng)是有標準的代碼模板了,所以我這里也沒什么創(chuàng)新的地方,照抄就完事了,這里便淺淺介紹一下測量的步驟吧。 其流程是:

  • 先用getMode()和getSize()獲取測量模式和寬高,再根據(jù)不同的模式獲取寬高。
  • 模式有三種:EXACTLY(精確值模式)、AT_MOST(最大值模式)、UNSPECIFIED(未指定模式)
  • 如果是EXACTLY(精確值模式),那么該屬性就是確定的,即當前View的寬高
  • 如果是AT_MOST(最大值模式),那么該屬性就是父容器的寬高
  • 如果是UNSPECIFIED(未指定模式),那么該屬性要么是0,要么是EXACTLY(精確值模式)下當前view的屬性。 用圖來說明,即為:

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        /**
         * 從提供的測量規(guī)格中獲取測量模式和寬高值
         */
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        Log.d("TAG", "onMeasure: "+widthMode);
        Log.d("TAG", "onMeasure: "+widthSize);
        if (widthMode == MeasureSpec.EXACTLY) {
            //測量模式是EXACTLY,說明view的寬度值是確定的
            mWidth = widthSize;
        } else if (widthMode == MeasureSpec.AT_MOST) {
            /**
             * 測量模式是AT_MOST,說明view的寬度值最大是父View能提供的大小
             * 比如開發(fā)者設(shè)置wrap_content,那可能是希望填充父View
             */
            mWidth = Math.max(mWidth,widthSize);
        }
        if (heightMode == MeasureSpec.EXACTLY) {
            mHeight = heightSize;
        } else if (heightMode == MeasureSpec.AT_MOST) {
            mHeight = Math.min(mHeight,heightSize);
        }
        /**
         * 為了View能更好的展示,需要設(shè)置下寬高比
         */
        float times = mWidth / (float)mHeight;
        if (times < 2.5 ) {
            if (mHeight < DensityUtil.dip2px(getContext(),60)) {
                mHeight = DensityUtil.dip2px(getContext(),60);
            }
            mWidth = (int) (mHeight * 2.5);
        }
        mRadius = (int) getContext().getResources().getDimension(R.dimen.base_dp_20);
        //保存計算后的寬高
        setMeasuredDimension(mWidth,mHeight);
    }

3.根據(jù)情況來畫漸變色進度

這里因為需求原因,我將原本的進度條五色平分進度,所以這里用到已經(jīng)測量好的寬度屬性mWidth 。 這里的流程也很簡單,簡要說下

  • 暴露方法給外界調(diào)用
  • 獲取進度
  • 根據(jù)進度來給漸變?nèi)旧鳎篖inearGradient初始化
  • 同時給圓柱形RectF初始化寬高
  • 最后調(diào)用invalidate()重新繪制該View
 public void setAirType(String degree){
        int level = mWidth / 5;
        switch (degree){
            case "1":
                mGradientRect = new RectF(0,0,level,mHeight);
                // 因為漸變色集合,需要顏色大于等于2,這里取巧,設(shè)置相同顏色
                backGradient = new LinearGradient(0, 0, level, 0, new int[]{colorStart,colorStart}, null, Shader.TileMode.CLAMP);
                break;
            case "2":
                mGradientRect = new RectF(0,0,level*2,mHeight);
                backGradient = new LinearGradient(0, 0, level*2, 0, new int[]{colorStart, colorStart2}, null, Shader.TileMode.CLAMP);
                break;
            case "3":
                mGradientRect = new RectF(0,0,level*3,mHeight);
                backGradient = new LinearGradient(0, 0, level*3, 0, new int[]{colorStart, colorStart2,colorCenter}, null, Shader.TileMode.CLAMP);
                break;
            case "4":
                mGradientRect = new RectF(0,0,level*4,mHeight);
                backGradient = new LinearGradient(0, 0, level*4, 0, new int[]{colorStart, colorStart2,colorCenter,colorEnd0}, null, Shader.TileMode.CLAMP);
                break;
            case "5":
                mGradientRect = new RectF(0,0,mWidth,mHeight);
                backGradient = new LinearGradient(0, 0, mWidth, 0, new int[]{colorStart, colorStart2,colorCenter,colorEnd0,colorEnd}, null, Shader.TileMode.CLAMP);
                break;
        }
        invalidate();
    }

4.繪制

這里我采用最簡單粗暴的方法,直接疊了兩個圓柱進度條,一個是原色的進度條,一個是漸變色的進度條,這里大家可以自行優(yōu)化,即在backGradient 屬性初始化的時候進度調(diào)整等。

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawRoundRect(canvas);
    }
    private void drawRoundRect(Canvas canvas) {
        mBackGroundRect.left = 0;
        mBackGroundRect.top = 0;
        mBackGroundRect.bottom = mHeight;
        mBackGroundRect.right = mWidth;
        // 繪制底色圓角矩形
        canvas.drawRoundRect(mBackGroundRect, mRadius, mRadius, mPaint);
        // 漸變繪圖
        mGradientPaint.setShader(backGradient);
        //繪制背景 圓角矩形
        if (mGradientRect != null) {
            canvas.drawRoundRect(mGradientRect, mRadius, mRadius, mGradientPaint);
        }
    }

完整代碼貼上,方便各位友友使用

public class GradientProgressView extends View {
    private int colorStart; // 顏色:進度1
    private int colorEnd; // 顏色:進度5
    private int colorStart2;// 顏色:進度2
    private int colorEnd0;// 顏色:進度4
    private int colorCenter;// 顏色:進度3
    private List<Integer> colorList; // 顏色集合
    private List<Float> colorSize; // 顏色位置
    private Paint mGradientPaint;// 漸變畫筆
    private Paint mPaint;// 默認畫筆
    private RectF mBackGroundRect; // 原色圖形
    private RectF mGradientRect;// 染色圖形
    private LinearGradient backGradient;// 漸變色
    private int mHeight;
    private int mWidth;
    private int mRadius;
    public GradientProgressView(Context context) {
        super(context);
    }
    public GradientProgressView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context,attrs);
    }
    public GradientProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    private void init(Context context, @Nullable AttributeSet attrs){
        // 初始化畫筆
        mGradientPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        colorStart = Color.parseColor("#63DC80");
        colorStart2 = Color.parseColor("#A8DB5B");
        colorCenter = Color.parseColor("#FFCE48");
        colorEnd0 = Color.parseColor("#FE7B39");
        colorEnd = Color.parseColor("#E8402B");
        mPaint.setColor(Color.parseColor("#EDEDED"));
        if (attrs!=null){
        }
        //設(shè)置抗鋸齒
        mGradientPaint.setAntiAlias(true);
        //設(shè)置防抖動
        mGradientPaint.setDither(true);
        mGradientPaint.setStyle(Paint.Style.FILL);
        //設(shè)置抗鋸齒
        mPaint.setAntiAlias(true);
        //設(shè)置防抖動
        mPaint.setDither(true);
        mPaint.setStyle(Paint.Style.FILL);
        mBackGroundRect = new RectF();
        // 防止渲染還未完成就顯示,使得寬高還未測量。先在初始化這里定義好跟xml中相同的寬高
        mWidth = (int) (Resources.getSystem().getDisplayMetrics().widthPixels-context.getResources().getDimension(R.dimen.base_dp_56));
        mHeight = (int) (context.getResources().getDimension(R.dimen.base_dp_8));
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        /**
         * 從提供的測量規(guī)格中獲取測量模式和寬高值
         */
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        Log.d("TAG", "onMeasure: "+widthMode);
        Log.d("TAG", "onMeasure: "+widthSize);
        if (widthMode == MeasureSpec.EXACTLY) {
            //測量模式是EXACTLY,說明view的寬度值是確定的
            mWidth = widthSize;
        } else if (widthMode == MeasureSpec.AT_MOST) {
            /**
             * 測量模式是AT_MOST,說明view的寬度值最大是父View能提供的大小
             * 比如開發(fā)者設(shè)置wrap_content,那可能是希望填充父View
             */
            mWidth = Math.max(mWidth,widthSize);
        }
        if (heightMode == MeasureSpec.EXACTLY) {
            mHeight = heightSize;
        } else if (heightMode == MeasureSpec.AT_MOST) {
            mHeight = Math.min(mHeight,heightSize);
        }
        /**
         * 為了View能更好的展示,需要設(shè)置下寬高比
         */
        float times = mWidth / (float)mHeight;
        if (times < 2.5 ) {
            if (mHeight < DensityUtil.dip2px(getContext(),60)) {
                mHeight = DensityUtil.dip2px(getContext(),60);
            }
            mWidth = (int) (mHeight * 2.5);
        }
        mRadius = (int) getContext().getResources().getDimension(R.dimen.base_dp_20);
        //保存計算后的寬高
        setMeasuredDimension(mWidth,mHeight);
    }
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
          mWidth = w;
          mHeight = h;
    }
    public void setAirType(String degree){
        int level = mWidth / 5;
        switch (degree){
            case "1":
                mGradientRect = new RectF(0,0,level,mHeight);
                // 因為漸變色集合,需要顏色大于等于2,這里取巧,設(shè)置相同顏色
                backGradient = new LinearGradient(0, 0, level, 0, new int[]{colorStart,colorStart}, null, Shader.TileMode.CLAMP);
                break;
            case "2":
                mGradientRect = new RectF(0,0,level*2,mHeight);
                backGradient = new LinearGradient(0, 0, level*2, 0, new int[]{colorStart, colorStart2}, null, Shader.TileMode.CLAMP);
                break;
            case "3":
                mGradientRect = new RectF(0,0,level*3,mHeight);
                backGradient = new LinearGradient(0, 0, level*3, 0, new int[]{colorStart, colorStart2,colorCenter}, null, Shader.TileMode.CLAMP);
                break;
            case "4":
                mGradientRect = new RectF(0,0,level*4,mHeight);
                backGradient = new LinearGradient(0, 0, level*4, 0, new int[]{colorStart, colorStart2,colorCenter,colorEnd0}, null, Shader.TileMode.CLAMP);
                break;
            case "5":
                mGradientRect = new RectF(0,0,mWidth,mHeight);
                backGradient = new LinearGradient(0, 0, mWidth, 0, new int[]{colorStart, colorStart2,colorCenter,colorEnd0,colorEnd}, null, Shader.TileMode.CLAMP);
                break;
        }
        invalidate();
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawRoundRect(canvas);
    }
    private void drawRoundRect(Canvas canvas) {
        mBackGroundRect.left = 0;
        mBackGroundRect.top = 0;
        mBackGroundRect.bottom = mHeight;
        mBackGroundRect.right = mWidth;
        // 繪制底色圓角矩形
        canvas.drawRoundRect(mBackGroundRect, mRadius, mRadius, mPaint);
        // 漸變繪圖
        mGradientPaint.setShader(backGradient);
        //繪制背景 圓角矩形
        if (mGradientRect != null) {
            canvas.drawRoundRect(mGradientRect, mRadius, mRadius, mGradientPaint);
        }
    }
}

xml調(diào)用

        <com.itaem.blviewtest.GradientProgressView
            android:id="@+id/gradientProgress"
            android:layout_width="match_parent"
            android:layout_height="@dimen/base_dp_8"
            android:layout_marginTop="12dp"
            android:layout_marginHorizontal="@dimen/base_dp_44"/>

總結(jié)

還是因為時間問題,該自定義View只是單純滿足需求,并沒有太大的擴展性功能,后續(xù)有時間我也行會出一篇后續(xù)將自定義View補上,實現(xiàn)一個功能性較為強大的漸變色進度條。 自定義View的魅力就是當你實現(xiàn)功能需求的時候的滿足感,不亞于以前做完一道數(shù)學大題。那種暢快和欣喜,老實說我有點愛上自定義View了。

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

相關(guān)文章

最新評論