公司项目想做个渐变效果,虽然最终没有实现出来,还是把自己的一点体会写出来。算是根据现象推测实现吧,没去研究源码怎么实现的。
直接上代码:
package com.wedgits; import android.animation.ValueAnimator; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.RectF; import android.graphics.SweepGradient; import android.support.v4.content.ContextCompat; import android.util.AttributeSet; import android.view.View; import com.puhui.lib.utils.DensityUtil; import com.renren.customview.R; /** * Copyright: ******* * Created by ******* on 2017/5/9. * Description: 环形进度 * Modified By: */ public class FanProgressBar extends View { /** * 画笔对象的引用 */ private Paint circlePaint; //底部圆环画笔 private Paint arcPaint; //上部圆弧画笔 private Paint topCirclePoint; //顶部圆点 private Path mPath; private boolean capRound; //画笔形状 private int roundColor; //圆环的颜色 private int roundProgressColor; //圆弧进度的颜色 private float roundWidth; //圆环的宽度 private int maxProgress = 100; //最大进度 private float progress; //当前进度 private int style = STROKE; //进度的风格,实心或者空心 public static final int STROKE = 0; public static final int FILL = 1; public FanProgressBar(Context context) { this(context, null); } public FanProgressBar(Context context, AttributeSet attrs) { this(context, attrs, 0); } public FanProgressBar(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.FanProgressBar); // 获取自定义属性和默认值 roundColor = mTypedArray.getColor(R.styleable.FanProgressBar_bgColor, Color.RED); roundProgressColor = mTypedArray.getColor(R.styleable.FanProgressBar_fgColor, Color.GREEN); roundWidth = mTypedArray.getDimension(R.styleable.FanProgressBar_fanRoundWidth, DensityUtil.dip2px(getContext(), 15)); progress = mTypedArray.getInt(R.styleable.FanProgressBar_fanProgress, 0); capRound = mTypedArray.getBoolean(R.styleable.FanProgressBar_capRound, true); mTypedArray.recycle(); } private RectF mOval; private SweepGradient sweepGradient; private static final int[] colors = new int[]{Color.GREEN, Color.GREEN, Color.BLUE, Color.RED, Color.RED}; private float circleSize; @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); float size = Math.min(w, h); circleSize = size; mOval = new RectF(roundWidth / 2, roundWidth / 2, size - roundWidth / 2, size - roundWidth / 2); init(); } /** * 初始化操作 */ private void init() { circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG); circlePaint.setColor(roundColor); // 设置圆环的颜色 circlePaint.setStyle(Paint.Style.STROKE); // 设置空心 circlePaint.setStrokeWidth(roundWidth); // 设置圆环的宽度 circlePaint.setAntiAlias(true); // 消除锯齿 circlePaint.setStrokeCap(capRound ? Paint.Cap.ROUND : Paint.Cap.SQUARE); sweepGradient = new SweepGradient(mOval.centerX(), mOval.centerY(), colors, null); arcPaint = new Paint(); // arcPaint.setColor(roundProgressColor); // 设置圆环的颜色 arcPaint.setStyle(Paint.Style.STROKE); // 设置空心 arcPaint.setStrokeWidth(roundWidth); // 设置圆环的宽度 arcPaint.setAntiAlias(true); // 消除锯齿 arcPaint.setStrokeCap(capRound ? Paint.Cap.ROUND : Paint.Cap.SQUARE); arcPaint.setShader(sweepGradient); mPath = new Path(); // mPath.reset(); // mPath.addArc(mOval, 30, maxProgress); topCirclePoint = new Paint(); topCirclePoint.setColor(ContextCompat.getColor(getContext(), R.color.white)); // 设置圆环的颜色 topCirclePoint.setStyle(Paint.Style.FILL_AND_STROKE); topCirclePoint.setAntiAlias(true); // 消除锯齿 } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.rotate(-120, circleSize / 2, circleSize / 2); canvas.save(); canvas.drawArc(mOval, 0, 360, false, circlePaint); // 画出圆环 //画圆弧 ,画圆环的进度 // arcPaint.setColor(roundProgressColor); // 设置进度的颜色 // arcPaint.setShader(sweepGradient); switch (style) { case STROKE: { // Paint p = new Paint(); // 参数一为渐变起初点坐标x位置,参数二为y轴位置,参数三和四分辨对应渐变终点,最后参数为平铺方式,这里设置为镜像 // Gradient是基于Shader类,所以我们通过Paint的setShader方法来设置这个渐变 // LinearGradient lg = new LinearGradient(0, 0, 400, 400, colors, positions, Shader.TileMode.MIRROR); // arcPaint.setShader(lg); // mPath.reset(); // mPath.addArc(mOval, 30, progress); // canvas.drawPath(mPath, arcPaint); canvas.drawArc(mOval, 30, progress, false, arcPaint); // 根据进度画圆弧 break; } case FILL: { arcPaint.setStyle(Paint.Style.FILL_AND_STROKE); if (progress != 0) canvas.drawArc(mOval, 0, 360 * progress / maxProgress, true, arcPaint); // 根据进度画圆弧 break; } } canvas.drawCircle(mOval.centerX(), roundWidth / 2, DensityUtil.dip2px(getContext(), 4), topCirclePoint); canvas.restore(); } /** * 获取进度.需要同步 */ public synchronized float getProgress() { return progress; } public void setMaxProgress(int maxProgress) { this.maxProgress = maxProgress; } public int getMaxProgress() { return maxProgress; } /** * 设置进度,此为线程安全控件,由于考虑多线的问题,需要同步 刷新界面调用postInvalidate()能在非UI线程刷新 */ public void setProgress(int progress) { if (progress < 0) { progress = 0; } if (progress > maxProgress) { progress = maxProgress; } setAnimation(progress); } /** * 为进度设置动画 */ public void setAnimation(float progress) { ValueAnimator progressAnimator = ValueAnimator.ofFloat(0, progress); progressAnimator.setDuration(3000); progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { FanProgressBar.this.progress = (float) animation.getAnimatedValue(); invalidate(); } }); progressAnimator.start(); } }样式文件:
<declare-styleable name="FanProgressBar">
<attr name="bgColor" format="color" />
<attr name="fgColor" format="color" />
<attr name="fanRoundWidth" format="dimension" />
<attr name="fanProgress" format="integer" />
<attr name="capRound" format="boolean" />
</declare-styleable>
使用:
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) fanProgressBar.getLayoutParams();
layoutParams.width = DensityUtil.getScreenWidth(this) - DensityUtil.dip2px(this, 120);
layoutParams.height = DensityUtil.getScreenWidth(this) - DensityUtil.dip2px(this, 120);
fanProgressBar.setLayoutParams(layoutParams);
fanProgressBar.setMaxProgress(360);
fanProgressBar.setAnimation(fanProgressBar.getMaxProgress());
效果一:
效果二:
效果三:
效果四:(onDraw方法部分代码同效果三)
唉,纠结该怎么描述。
不管了,瞎说吧。
一、在我们给Paint设置shader(arcPaint.setShader(sweepGradient);)时,圆环的颜色占比就已经分配好了new int[]{Color.GREEN, Color.GREEN, Color.BLUE, Color.RED, Color.RED};,Green : Blue : Red = 2 : 1 : 2。而且是分配在整个圆环的。所以在Progress设置为360,200,120时,出现不同的效果,如效果一,效果四。
二、