最近项目中使用到了渐变效果的圆形进度条,网上找了很多渐变效果不够圆滑,两个渐变颜色之间有明显的过渡,或者有些代码画出来的效果过渡不美观,于是自己参照写了一个,喜欢的朋友可以参考或者直接使用。

先上一张效果图,视频录制不太好,不过不影响效果

android渐变圆环 android圆环进度条渐变_android

下面开始介绍实现代码,比较简单,直接贴代码吧

1、声明自定义属性

在项目的valuse文件夹下新建attrs.xml,在里面定义自定义控件需要的属性

2、自定义一个进度条RoundProgres继承view类

package com.blankj.progressring;

import android.animation.ValueAnimator;

import android.content.Context;

import android.content.res.TypedArray;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Matrix;

import android.graphics.Paint;

import android.graphics.Rect;

import android.graphics.RectF;

import android.graphics.SweepGradient;

import android.graphics.Typeface;

import android.util.AttributeSet;

import android.util.Log;

import android.view.View;

import android.view.animation.LinearInterpolator;

import org.jetbrains.annotations.Nullable;

/**

* 类描述:渐变的圆形进度条

*

* @author:lusy

* @date :2018/10/17

*/

public class RoundProgress extends View {

private static final String TAG = "roundProgress";

/**

* 背景圆环画笔

*/

private Paint bgPaint;

/**

* 白色标记画笔

*/

private Paint iconPaint;

/**

* 进度画笔

*/

private Paint progressPaint;

/**

* 进度文本画笔

*/

private Paint textPaint;

/**

* 背景圆环的颜色

*/

private int bgColor;

/**

* 线条进度的颜色

*/

private int iconColor;

private int[] progressColor;

/**

* 中间进度百分比的字符串的颜色

*/

private int textColor;

/**

* 中间进度百分比的字符串的字体大小

*/

private float textSize;

/**

* 圆环的宽度

*/

private float roundWidth;

/**

* 最大进度

*/

private int max;

/**

* 当前进度

*/

private float progress;

/**

* 是否显示中间的进度

*/

private boolean textIsDisplayable;

/**

* 圆环半径

*/

private int mRadius;

private int center;

private float startAngle = -90;

private float currentAngle;

private float currentProgress;

public RoundProgress(Context context) {

this(context, null);

}

public RoundProgress(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundProgress);

//获取自定义属性和默认值

bgColor = mTypedArray.getColor(R.styleable.RoundProgress_bgColor, Color.parseColor("#2d2d2d"));

iconColor = mTypedArray.getColor(R.styleable.RoundProgress_lineColor, Color.parseColor("#ffffff"));

textColor = mTypedArray.getColor(R.styleable.RoundProgress_textColor, Color.parseColor("#ffffff"));

textSize = mTypedArray.getDimension(R.styleable.RoundProgress_textSize, 15);

roundWidth = mTypedArray.getDimension(R.styleable.RoundProgress_roundWidth, 5);

max = mTypedArray.getInteger(R.styleable.RoundProgress_maxProgress, 100);

textIsDisplayable = mTypedArray.getBoolean(R.styleable.RoundProgress_textIsDisplayable, true);

progressColor = new int[]{Color.parseColor("#747eff"), Color.parseColor("#0018ff"), Color.TRANSPARENT};

mTypedArray.recycle();

initPaint();

}

public RoundProgress(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

//测量控件应占的宽高大小,此处非必需,只是为了确保布局中设置的宽高不一致时仍显示完整的圆

int measureWidth = MeasureSpec.getSize(widthMeasureSpec);

int measureHeight = MeasureSpec.getSize(heightMeasureSpec);

setMeasuredDimension(Math.min(measureWidth, measureHeight), Math.min(measureWidth, measureHeight));

}

private void initPaint() {

bgPaint = new Paint();

bgPaint.setStyle(Paint.Style.STROKE);

bgPaint.setAntiAlias(true);

bgPaint.setColor(bgColor);

bgPaint.setStrokeWidth(roundWidth);

iconPaint = new Paint();

iconPaint.setStyle(Paint.Style.STROKE);

iconPaint.setAntiAlias(true);

iconPaint.setColor(iconColor);

iconPaint.setStrokeWidth(roundWidth);

progressPaint = new Paint();

progressPaint.setStyle(Paint.Style.STROKE);

progressPaint.setAntiAlias(true);

progressPaint.setStrokeWidth(roundWidth);

textPaint = new Paint();

textPaint.setStyle(Paint.Style.STROKE);

textPaint.setTypeface(Typeface.DEFAULT_BOLD);

textPaint.setAntiAlias(true);

textPaint.setColor(textColor);

textPaint.setTextSize(textSize);

textPaint.setStrokeWidth(0);

}

@Override

protected void onDraw(Canvas canvas) {

/**

* 画最外层的大圆环

*/

//获取圆心的x坐标

center = Math.min(getWidth(), getHeight()) / 2;

// 圆环的半径

mRadius = (int) (center - roundWidth / 2);

RectF oval = new RectF(center - mRadius, center - mRadius, center + mRadius, center + mRadius);

//画背景圆环

canvas.drawArc(oval, startAngle, 360, false, bgPaint);

//画进度圆环

drawProgress(canvas, oval);

canvas.drawArc(oval, startAngle, currentAngle, false, progressPaint);

//画白色圆环

float start = startAngle + currentAngle - 1;

canvas.drawArc(oval, start, 3, false, iconPaint);

//百分比文字

int percent = (int) (((float) progress / (float) max) * 100);

//测量字体宽度,我们需要根据字体的宽度设置在圆环中间

String text = String.valueOf(percent)+"%";

Rect textRect = new Rect();

textPaint.getTextBounds(text, 0, text.length(), textRect);

if (textIsDisplayable && percent >= 0) {

//画出进度百分比文字

float x = (getWidth() - textRect.width()) / 2;

float y = (getHeight() + textRect.height()) / 2;

canvas.drawText(text, x, y, textPaint);

}

if (currentProgress < progress) {

currentProgress++;

postInvalidate();

}

}

/**

* 画进度圆环

*

* @param canvas

* @param oval

*/

private void drawProgress(Canvas canvas, RectF oval) {

float section = progress / 100;

currentAngle = section * 360;

//把需要绘制的角度分成100等分

float unitAngle = (float) (currentAngle / 100.0);

for (float i = 0, end = currentProgress * unitAngle; i <= end; i++) {

SweepGradient shader = new SweepGradient(center, center, progressColor, new float[]{0.0f, section, 1.0f});

Matrix matrix = new Matrix();

matrix.setRotate(startAngle, center, center);

shader.setLocalMatrix(matrix);

progressPaint.setShader(shader);

canvas.drawArc(oval,

startAngle + i,

1,

false,

progressPaint);

}

}

@Override

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

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

//计算外圆半径 宽,高最小值-填充边距/2

center = (Math.min(w, h)) / 2;

mRadius = (int) ((Math.min(w, h)) - roundWidth / 2);

}

public int getMax() {

return max;

}

/**

* 设置进度的最大值

*

* @param max

*/

public void setMax(int max) {

if (max < 0) {

Log.e(TAG, "max progress not allow <0");

return;

}

this.max = max;

}

/**

* 获取进度

*

* @return

*/

public float getProgress() {

return progress;

}

/**

* 设置进度

*

* @param progressValue

* @param useAnima 是否需要动画

*/

public void setProgress(float progressValue, boolean useAnima) {

float percent = progressValue * max / 100;

if (percent < 0) {

percent = 0;

}

if (percent > 100) {

percent = 100;

}

//使用动画

if (useAnima) {

ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, percent);

valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

progress = (float) animation.getAnimatedValue();

postInvalidate();

}

});

valueAnimator.setInterpolator(new LinearInterpolator());

valueAnimator.setDuration(1500);

valueAnimator.start();

} else {

this.progress = percent;

postInvalidate();

}

}

public int getTextColor() {

return textColor;

}

public void setTextColor(int textColor) {

this.textColor = textColor;

}

public float getTextSize() {

return textSize;

}

public void setTextSize(float textSize) {

this.textSize = textSize;

}

public float getRoundWidth() {

return roundWidth;

}

public void setRoundWidth(float roundWidth) {

this.roundWidth = roundWidth;

}

public int[] getProgressColor() {

return progressColor;

}

public void setProgressColor(int[] progressColor) {

this.progressColor = progressColor;

postInvalidate();

}

public int getBgColor() {

return bgColor;

}

public void setBgColor(int bgColor) {

this.bgColor = bgColor;

}

public int getIconColor() {

return iconColor;

}

public void setIconColor(int iconColor) {

this.iconColor = iconColor;

}

public boolean isTextIsDisplayable() {

return textIsDisplayable;

}

public void setTextIsDisplayable(boolean textIsDisplayable) {

this.textIsDisplayable = textIsDisplayable;

}

public int getmRadius() {

return mRadius;

}

public void setmRadius(int mRadius) {

this.mRadius = mRadius;

}

public int getCenter() {

return center;

}

public void setCenter(int center) {

this.center = center;

}

public float getStartAngle() {

return startAngle;

}

public void setStartAngle(float startAngle) {

this.startAngle = startAngle;

}

}

3、使用自定义进度条view

activity布局文件使用如下,为了方便测试效果,新增进度加、进度减,修改进度条颜色的按钮

xmlns:app="http://schemas.android.com/apk/res-auto"

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="#242424"

android:gravity="center">

android:id="@+id/buttonLayout"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_margin="20dp"

android:gravity="center_horizontal"

android:orientation="horizontal">

android:id="@+id/addProgress"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="进度+" />

android:id="@+id/changeColor"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginLeft="10dp"

android:layout_marginRight="10dp"

android:text="设置颜色" />

android:id="@+id/subtraceProgress"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="进度-" />

android:id="@+id/socProgress"

android:layout_width="70dp"

android:layout_height="70dp"

android:layout_below="@id/buttonLayout"

android:layout_centerHorizontal="true"

android:layout_gravity="center"

android:layout_marginLeft="20dp"

android:layout_marginBottom="2dp"

app:bgColor="@color/bgColor"

app:maxProgress="100"

app:roundWidth="8dp"

app:textIsDisplayable="true"

app:textSize="18sp" />

以上就是本文的全部内容,希望对大家的学习有所帮助