亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

前言

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

一、GradientProgressView準(zhǔn)備工作

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

二、繪制

1.初始化屬性

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

    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è)置防抖動(dòng)
        mGradientPaint.setDither(true);
        mGradientPaint.setStyle(Paint.Style.FILL);
        //設(shè)置抗鋸齒
        mPaint.setAntiAlias(true);
        //設(shè)置防抖動(dòng)
        mPaint.setDither(true);
        mPaint.setStyle(Paint.Style.FILL);
        mBackGroundRect = new RectF();
        // 防止渲染還未完成就顯示,使得寬高還未測(cè)量。先在初始化這里定義好跟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.測(cè)量寬高

這一步一般來(lái)說(shuō)已經(jīng)是有標(biāo)準(zhǔn)的代碼模板了,所以我這里也沒(méi)什么創(chuàng)新的地方,照抄就完事了,這里便淺淺介紹一下測(cè)量的步驟吧。 其流程是:

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

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        /**
         * 從提供的測(cè)量規(guī)格中獲取測(cè)量模式和寬高值
         */
        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) {
            //測(cè)量模式是EXACTLY,說(shuō)明view的寬度值是確定的
            mWidth = widthSize;
        } else if (widthMode == MeasureSpec.AT_MOST) {
            /**
             * 測(cè)量模式是AT_MOST,說(shuō)明view的寬度值最大是父View能提供的大小
             * 比如開(kāi)發(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);
        //保存計(jì)算后的寬高
        setMeasuredDimension(mWidth,mHeight);
    }

3.根據(jù)情況來(lái)畫漸變色進(jìn)度

這里因?yàn)樾枨笤颍覍⒃镜倪M(jìn)度條五色平分進(jìn)度,所以這里用到已經(jīng)測(cè)量好的寬度屬性mWidth 。 這里的流程也很簡(jiǎn)單,簡(jiǎn)要說(shuō)下

  • 暴露方法給外界調(diào)用
  • 獲取進(jìn)度
  • 根據(jù)進(jìn)度來(lái)給漸變?nèi)旧鳎篖inearGradient初始化
  • 同時(shí)給圓柱形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);
                // 因?yàn)闈u變色集合,需要顏色大于等于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.繪制

這里我采用最簡(jiǎn)單粗暴的方法,直接疊了兩個(gè)圓柱進(jìn)度條,一個(gè)是原色的進(jìn)度條,一個(gè)是漸變色的進(jìn)度條,這里大家可以自行優(yōu)化,即在backGradient 屬性初始化的時(shí)候進(jìn)度調(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; // 顏色:進(jìn)度1
    private int colorEnd; // 顏色:進(jìn)度5
    private int colorStart2;// 顏色:進(jìn)度2
    private int colorEnd0;// 顏色:進(jìn)度4
    private int colorCenter;// 顏色:進(jìn)度3
    private List<Integer> colorList; // 顏色集合
    private List<Float> colorSize; // 顏色位置
    private Paint mGradientPaint;// 漸變畫筆
    private Paint mPaint;// 默認(rèn)畫筆
    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è)置防抖動(dòng)
        mGradientPaint.setDither(true);
        mGradientPaint.setStyle(Paint.Style.FILL);
        //設(shè)置抗鋸齒
        mPaint.setAntiAlias(true);
        //設(shè)置防抖動(dòng)
        mPaint.setDither(true);
        mPaint.setStyle(Paint.Style.FILL);
        mBackGroundRect = new RectF();
        // 防止渲染還未完成就顯示,使得寬高還未測(cè)量。先在初始化這里定義好跟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);
        /**
         * 從提供的測(cè)量規(guī)格中獲取測(cè)量模式和寬高值
         */
        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) {
            //測(cè)量模式是EXACTLY,說(shuō)明view的寬度值是確定的
            mWidth = widthSize;
        } else if (widthMode == MeasureSpec.AT_MOST) {
            /**
             * 測(cè)量模式是AT_MOST,說(shuō)明view的寬度值最大是父View能提供的大小
             * 比如開(kāi)發(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);
        //保存計(jì)算后的寬高
        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);
                // 因?yàn)闈u變色集合,需要顏色大于等于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é)

還是因?yàn)闀r(shí)間問(wèn)題,該自定義View只是單純滿足需求,并沒(méi)有太大的擴(kuò)展性功能,后續(xù)有時(shí)間我也行會(huì)出一篇后續(xù)將自定義View補(bǔ)上,實(shí)現(xiàn)一個(gè)功能性較為強(qiáng)大的漸變色進(jìn)度條。 自定義View的魅力就是當(dāng)你實(shí)現(xiàn)功能需求的時(shí)候的滿足感,不亞于以前做完一道數(shù)學(xué)大題。那種暢快和欣喜,老實(shí)說(shuō)我有點(diǎn)愛(ài)上自定義View了。

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

相關(guān)文章

最新評(píng)論