美文网首页
实现圆形头部渐变进度条的一种方案

实现圆形头部渐变进度条的一种方案

作者: 灰狼Allan | 来源:发表于2020-02-26 16:37 被阅读0次

实现渐变进度条的一种方案,解决进度小于头部半圆时变形的问题。

image

上方的进度条为系统的ProgressBar,可以看到,第二个进度条progress背景发生了变形(比如progress设置为1)。

custom_progress_primary.xml


<?xml version="1.0" encoding="utf-8"?>

<shape xmlns:android="http://schemas.android.com/apk/res/android">

    <corners android:radius="10dp" />

    <solid android:color="@color/colorAccent" />

</shape>

bg_progressbar.xml


<?xml version="1.0" encoding="utf-8"?>

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:id="@android:id/background">

        <shape android:shape="rectangle">

            <corners android:radius="15dp" />

            <solid android:color="#eeeeee" />

    <item android:id="@android:id/progress">

            android:drawable="@drawable/custom_progress_primary"

            android:scaleWidth="98%" />

</layer-list>

布局中的代码:


    android:id="@+id/progress_first"

    style="?android:attr/progressBarStyleHorizontal"

    android:layout_width="0dp"

    android:layout_height="15dp"

    android:layout_marginTop="12dp"

    android:layout_marginRight="20dp"

    android:max="100"

    android:progress="50"

    android:progressDrawable="@drawable/bg_progressbar"

    app:layout_constraintLeft_toLeftOf="@id/tv_first"

    app:layout_constraintRight_toRightOf="parent"

    app:layout_constraintTop_toBottomOf="@id/tv_first" />

核心代码即为:paint.setXfermode(new PorterDuffXfermode(mode));在进度小于半圆时,使用混合模式绘制两个圆相交的形状。以下为CornerProgressBar的代码


package com.allan.demo.widget;

import android.content.Context;

import android.content.res.TypedArray;

import android.graphics.Bitmap;

import android.graphics.Canvas;

import android.graphics.LinearGradient;

import android.graphics.Paint;

import android.graphics.PaintFlagsDrawFilter;

import android.graphics.PorterDuff;

import android.graphics.PorterDuffXfermode;

import android.graphics.Shader;

import android.util.AttributeSet;

import android.view.View;

import com.allan.demo.R;

import java.math.BigDecimal;

public class CornerProgressBarextends View {

private static final int DEFAULT_MAX =100;

    private static final int DEFAULT_PROGRESS =0;

    private static final int DEFAULT_START_COLOR =0xFFFFE60D;

    private static final int DEFAULT_END_COLOR =0xFFFFC629;

    private static final int DEFAULT_BACKGROUD_COLOR =0xFFEFF1F4;

    private static final int DEFAULT_TEXT_COLOR =0xFF333333;

    private static final int DEFAULT_TEXT_SIZE =14;

    private double mMax =DEFAULT_MAX;

    private double mProgress =DEFAULT_PROGRESS;//当前进度

    private int mColor0 =DEFAULT_START_COLOR;//开始渐变色

    private int mColor1 =DEFAULT_END_COLOR;//结束渐变色

    private int mColorBackgroud =DEFAULT_BACKGROUD_COLOR;//背景色

    private int mTextColor =DEFAULT_TEXT_COLOR;

    private float mTextSize;//字体大小

    private Paintpaint;

    private PaintmBackgroudPaint;

    private PorterDuff.Modemode;

    public CornerProgressBar(Context context) {

super(context);

        initStyle(context, null, 0, 0);

        initPaint();

    }

public CornerProgressBar(Context context, AttributeSet attrs) {

super(context, attrs);

        initStyle(context, attrs, 0, 0);

        initPaint();

    }

public CornerProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

        initStyle(context, attrs, defStyleAttr, 0);

        initPaint();

    }

public CornerProgressBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {

super(context, attrs, defStyleAttr, defStyleRes);

        initStyle(context, attrs, defStyleAttr, defStyleRes);

        initPaint();

    }

/**

    * 当progress大于max时,显示格式为150%,200%

*

    * @param max

    */

    public void setMax(double max) {

if (max <0) {

max =0;

        }

this.mMax = max;

//        if (mProgress > max) {

//            mProgress = max;

//        }

        invalidate();

    }

/**

    * 不设定上限 当progress大于max时,显示格式为150%,200%

*

    * @param progress

    */

    public void setProgress(double progress) {

if (progress <0) {

progress =0;

        }

//        if (progress > mMax) {

//            progress = mMax;

//        }

        this.mProgress = progress;

        invalidate();

    }

public double getProgress() {

return mProgress;

    }

public double getMax() {

return mMax;

    }

private void initStyle(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {

TypedArray array = getContext().obtainStyledAttributes(attrs, R.styleable.CornerProgressBar, defStyleAttr, defStyleRes);

        mMax = array.getInt(R.styleable.CornerProgressBar_barMax, DEFAULT_MAX);

        mProgress = array.getInt(R.styleable.CornerProgressBar_barProgress, DEFAULT_PROGRESS);

        mColor0 = array.getColor(R.styleable.CornerProgressBar_barStartColor, DEFAULT_START_COLOR);

        mColor1 = array.getColor(R.styleable.CornerProgressBar_barStartColor, DEFAULT_END_COLOR);

        mColorBackgroud = array.getColor(R.styleable.CornerProgressBar_barBackColor, DEFAULT_BACKGROUD_COLOR);

        mTextColor = array.getColor(R.styleable.CornerProgressBar_barTextColor, DEFAULT_TEXT_COLOR);

        final float scale = getResources().getDisplayMetrics().density;

        float defaultTextSize =DEFAULT_TEXT_SIZE * scale +0.5f;

        mTextSize = array.getDimension(R.styleable.CornerProgressBar_barTextSize, defaultTextSize);

        array.recycle();

    }

private void initPaint() {

paint =new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);

        paint.setStrokeWidth(getHeight());

        paint.setStrokeCap(Paint.Cap.ROUND);

        mBackgroudPaint =new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);

        mBackgroudPaint.setColor(mColorBackgroud);

        mBackgroudPaint.setStrokeCap(Paint.Cap.ROUND);

        mode = PorterDuff.Mode.SRC_IN;

    }

@Override

    protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

        paint.setStrokeWidth(getHeight());

        mBackgroudPaint.setStrokeWidth(getHeight());

        invalidate();

    }

/**

    * 计算进度宽度

    */

    private int calProgressWidth() {

int width = getWidth();

        int progressWidth = (int) (mProgress /mMax * width);

        return progressWidth <= width ? progressWidth : width;//最大宽度不超过进度条总宽度 但数值可以超过最大数值

    }

public double getProgressPercent() {

return mProgress /mMax;

    }

@Override

    protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

        if (getWidth() ==0) {

return;

        }

float radius = (float) getHeight() /2;

        float offsetBackgroundWidth = getWidth() - radius;

        int progressWidth = calProgressWidth();

        float offsetProgressWidth = progressWidth - radius;//需要绘制的长度是控件长度减去左右半圆的宽,即结束x坐标为宽-半径

        canvas.drawLine(radius, radius, offsetBackgroundWidth, radius, mBackgroudPaint);

        LinearGradient linearGradient =new LinearGradient(0, 0, progressWidth, 0, mColor0, mColor1, Shader.TileMode.CLAMP);

        paint.setShader(linearGradient);

        if (progressWidth > getHeight()) {

canvas.drawLine(radius, radius, offsetProgressWidth, radius, paint);

        }else {

Canvas canvas2 =new Canvas();

            int savedState = canvas.save();

            canvas2.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));//抗锯齿

            Bitmap bt = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);

            canvas2.setBitmap(bt);

            canvas2.drawCircle(radius, radius, radius, paint);

            Bitmap bt2 = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);

            canvas2.setBitmap(bt2);

            canvas2.drawCircle(progressWidth - radius, radius, radius, paint);

            canvas.saveLayer(0, 0, getWidth(), getHeight(), paint,

                    Canvas.ALL_SAVE_FLAG);

            canvas.drawBitmap(bt, 0, 0, paint);

            paint.setXfermode(new PorterDuffXfermode(mode));

            //注意这里savelayer的paint 是有叠加模式的!!!!!!!!!!!!!!!!!

            canvas.saveLayer(0, 0, getWidth(), getHeight(), paint,

                    Canvas.ALL_SAVE_FLAG);

            paint.setXfermode(null);//注意这里需要吧叠加模式制空 不然会与layer的空位图 进行叠加

            canvas.drawBitmap(bt2, 0, 0, paint);

            canvas.restoreToCount(savedState);

        }

drawProgressText(canvas);

    }

private void drawProgressText(Canvas canvas) {

String result;

        if (mMax !=0) {

BigDecimal progressDecimal = BigDecimal.valueOf(mProgress);

            BigDecimal maxDecimal = BigDecimal.valueOf(mMax);

            BigDecimal decimalHundred = BigDecimal.valueOf(100);

            BigDecimal decimalPercent = progressDecimal.divide(maxDecimal, 3, BigDecimal.ROUND_HALF_UP);

            BigDecimal decimalResult = decimalPercent.multiply(decimalHundred);

            result = decimalResult.setScale(1, BigDecimal.ROUND_HALF_UP).toPlainString() +"%";

        }else {

result ="0.0%";

        }

Paint.FontMetrics fontMetrics =new Paint.FontMetrics();

        paint.setTextSize(mTextSize);

        paint.getFontMetrics(fontMetrics);

        paint.setShader(null);

        paint.setColor(mTextColor);

        float topOffset = (float) getHeight() /2 - (fontMetrics.descent + fontMetrics.ascent) /2;

        float textWidth =paint.measureText(result);

        float leftOffset = (((float) getWidth() - textWidth)) /2;

//        LogUtil.e("drawProgressText", "current=" + text + " width=" + getWidth() + " topOffset=" + topOffset + " textWidth=" + textWidth + " leftOffset=" + leftOffset);

        canvas.drawText(result, leftOffset, topOffset, paint);

    }

}


<declare-styleable name="CornerProgressBar">

    <attr name="barTextSize" format="dimension|reference" />

    <attr name="barTextColor" format="color|reference" />

    <attr name="barStartColor" format="color|reference" />

    <attr name="barEndColor" format="color|reference" />

    <attr name="barBackColor" format="color|reference" />

    <attr name="barMax" format="integer|reference" />

    <attr name="barProgress" format="integer|reference" />

</declare-styleable>

相关文章

网友评论

      本文标题:实现圆形头部渐变进度条的一种方案

      本文链接:https://www.haomeiwen.com/subject/lzybchtx.html