不规则色块,且每到一个阶段,该色块变色的一个自定义进度条view
直接上图和代码
所有颜色可配,色块数量根据数据动态可变,边上带的标签没放出来,有需要可以找我,根据该view暴露出来的方法很容易算出来。
暂时没做太多优化,有时间会改一波
/** * Created by miaojun on 2018/6/6. * mail:[email protected] * * 可独立使用的底部不规则色块的进度条 */ public class ProgressIrregularView extends View { private int mStrokeWidth = 5;//描边宽度 private float mProgressHigh;//进度条总高度 private float mProgressWidth;//进度条总宽度 private int mPartNum;//分隔的份数 private int mDividerWidth = 5;//分割线的宽度 private int mBackgroundColor = Color.parseColor("#33ffffff");//底色 private int mDefaultBlockColor = Color.parseColor("#1a000000");//默认阶段色 private int mBlockColor = Color.parseColor("#33ff0f50");//当前阶段颜色 private int mProgressColor = Color.parseColor("#ff0f50");//进度条颜色 private int mProgressShapeColor = Color.parseColor("#ff6b23");//进度条中间渐变色 private Paint mPaint; private Path mPath; private List mDufaultList = new ArrayList();//默认色块坐标 private float mProp;//当前分数所占比例 private int mCurrentPart;//当前阶段 private float[] mProgressPosition; private ListmDefaultDataList;//默认色块分隔比例 private List mItemHeightList = new ArrayList<>();//各个色块高度 public ProgressIrregularView(Context context) { super(context); init(); } public ProgressIrregularView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } private void init(){ setLayerType(View.LAYER_TYPE_SOFTWARE, null); mPaint = new Paint(); mPath = new Path(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if(mProgressHigh == 0){ this.mProgressHigh = getMeasuredHeight(); this.mProgressWidth = getMeasuredWidth(); setProgress(mProp); } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); drawBackground(canvas); computeDefaultBlockPositionData(); drawDefaultBlock(canvas); if(mProgressPosition != null && mProgressPosition.length != 0 && mProp != 0){ float radi = (mProgressWidth - mStrokeWidth * 2) / 2; if(Math.abs(mProgressPosition[1] - mProgressPosition[3]) <= radi){ drawBottomArc(canvas,mProgressColor,mProgressPosition); }else if((mProgressHigh - 2 * mStrokeWidth) - Math.abs(mProgressPosition[1] - mProgressPosition[3]) <= radi){ drawTopArc(canvas,mProgressColor,mProgressPosition); }else{ drawBottomFilletBlock(canvas,mProgressColor,mProgressPosition); } } } //绘制底部背景 private void drawBackground(Canvas canvas){ mPaint.reset(); mPaint.setColor(mBackgroundColor); RectF rectF = new RectF(0,0,mProgressWidth,mProgressHigh); canvas.drawRoundRect(rectF,mProgressWidth/2,mProgressWidth/2, mPaint); } //绘制默认方形色块 private void drawDefaultBlock(Canvas canvas){ if(mDufaultList.size() == 0){ return; } if(mDufaultList.size() == 1){ drawOneDefaultBlock(canvas,mDefaultBlockColor, (float[]) mDufaultList.get(0)); return; } int currentColor; for(int i = 0; i < mDufaultList.size(); i++){ if(i >= mPartNum - mCurrentPart){ currentColor = mBlockColor; }else{ currentColor = mDefaultBlockColor; } if(i == 0){ drawTopFilletBlock(canvas,currentColor,(float[]) mDufaultList.get(i)); } else if(i == mDufaultList.size() - 1){ drawBottomFilletBlock(canvas,currentColor,(float[]) mDufaultList.get(i)); } else{ drawSquareBlock(canvas,currentColor,(float[]) mDufaultList.get(i)); } } } //计算默认阶段坐标 private void computeDefaultBlockPositionData(){ if(mDufaultList.size() != 0 || mDefaultDataList.size() == 0){ return; } float left = mStrokeWidth; float right = mProgressWidth - mStrokeWidth; float top,bottom,itemHigh; mPartNum = mDefaultDataList.size(); for(int i = 0; i < mPartNum; i++){ itemHigh = (mProgressHigh - mStrokeWidth * 2 - (mPartNum - 1) * mDividerWidth) * mDefaultDataList.get(i).getProp(); top = mStrokeWidth + getItemSum() + i * mDividerWidth; mItemHeightList.add(itemHigh); bottom = top + itemHigh; float[] itemPosition = {left,top,right,bottom}; mDufaultList.add(itemPosition); } } private float getItemSum(){ if(mItemHeightList.size() == 0){ return 0; } float sum = 0; for(float i : mItemHeightList){ sum = sum + i; } return sum; } //绘制矩形色块 private void drawSquareBlock(Canvas canvas,int color,float[] position){ mPaint.reset(); mPaint.setColor(color); RectF rectF = new RectF(position[0],position[1],position[2],position[3]); canvas.drawRect(rectF,mPaint); } //绘制上圆角色块 private void drawTopFilletBlock(Canvas canvas,int color,float[] position){ mPath.reset(); mPaint.reset(); mPaint.setColor(color); RectF rectF = new RectF(position[0],position[1],position[2],position[3]); float radi = (mProgressWidth - mStrokeWidth * 2) / 2; float[] topRadii={radi,radi,radi,radi,0f,0f,0f,0f}; mPath.addRoundRect(rectF,topRadii, Path.Direction.CW); canvas.drawPath(mPath, mPaint); } //绘制圆角矩形&矩形相交(头部半圆部分) private void drawTopArc(Canvas canvas,int color,float[] position){ int layoutId = canvas.saveLayer(0,0,mProgressWidth,mProgressHigh,null,Canvas.ALL_SAVE_FLAG); RectF rectF = new RectF(position[0],mStrokeWidth,position[2],position[1]); if(position[1] == mStrokeWidth){ return; }else{ position[1] = mStrokeWidth; } drawOneDefaultBlock(canvas,color,position); mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); canvas.drawRect(rectF,mPaint); canvas.restoreToCount(layoutId); } //绘制下半圆 private void drawBottomArc(Canvas canvas,int color,float[] position){ mPaint.reset(); mPaint.setColor(color); float radi = (mProgressWidth - mStrokeWidth * 2) / 2; double angle = Math.toDegrees(Math.acos((radi - Math.abs(position[1]-position[3]))/radi) * 2);//圆弧角度 RectF rectF = new RectF(position[0],mProgressHigh - mStrokeWidth - radi * 2,position[2],mProgressHigh - mStrokeWidth); canvas.drawArc(rectF,(float) ((180 - angle)/2),(float) angle,false,mPaint); } //绘制下圆角色块 private void drawBottomFilletBlock(Canvas canvas,int color,float[] position){ mPaint.reset(); mPaint.setColor(color); RectF rectF = new RectF(position[0],position[1],position[2],position[3]); float radi = (mProgressWidth - mStrokeWidth * 2) / 2; float[] bottomRadii={0f,0f,0f,0f,radi,radi,radi,radi}; Shader shader = new LinearGradient(0,mStrokeWidth+radi,0,mProgressHigh-mStrokeWidth,new int[] {mProgressColor,mProgressShapeColor,mProgressColor},null, Shader.TileMode.REPEAT); mPaint.setShader(shader); mPath.reset(); mPath.addRoundRect(rectF,bottomRadii, Path.Direction.CW); canvas.drawPath(mPath, mPaint); } //上下都是圆角(只有一个默认色块) private void drawOneDefaultBlock(Canvas canvas,int color,float[] position){ mPaint.reset(); mPaint.setColor(color); float radii = (mProgressWidth - mStrokeWidth * 2) / 2; RectF rectF = new RectF(position[0],position[1],position[2],position[3]); canvas.drawRoundRect(rectF,radii,radii, mPaint); } private int getCurrentPart(float prop){ float part = 0; for(int i = mDefaultDataList.size() - 1; i >= 0; i--){ part = part + mDefaultDataList.get(i).getProp(); if(part > prop){ return mDefaultDataList.size() - i; } } return 1; } //设置当前进度 private void setProgress(float prop){ if(mProgressHigh == 0){ return; } float left = mStrokeWidth; float progressHigh = prop * (mProgressHigh - mStrokeWidth * 2); float top = mProgressHigh - mStrokeWidth - progressHigh; float right = mProgressWidth - mStrokeWidth; float bottom = mProgressHigh - mStrokeWidth; mProgressPosition = new float[]{left, top, right, bottom}; } /** * 配置进度条色值 默认0 不重设颜色 * @param defaultBgColor 默认色块颜色 * @param progressColor 进度条主色 * @param progressShapeColor 进度条中间渐变色 * @param currentPartColor 当前色块颜色 */ public void initSetting(int defaultBgColor,int progressColor,int progressShapeColor,int currentPartColor){ if(defaultBgColor != 0){ mDefaultBlockColor = defaultBgColor; } if(progressColor != 0){ mProgressColor = progressColor; } if(progressShapeColor != 0){ mProgressShapeColor = progressShapeColor; } if(currentPartColor != 0){ mBlockColor = currentPartColor; } } /** * 设置当前分数所占比例 * @param prop */ public void setCurrentProp(float prop){ if(mProp == prop){ return; } mProp = prop; mCurrentPart = getCurrentPart(prop); setProgress(prop); invalidate(); } //设置默认数据 public void setDefaultData(List list){ if(mDefaultDataList == null){ mDefaultDataList = new ArrayList<>(); mDefaultDataList.addAll(list); Collections.reverse(mDefaultDataList);//倒序 } } //获取各阶段高度 public List getItemHeightList(){ return mItemHeightList; } //获取分隔线高度 public int getStrokeWidth(){ return mStrokeWidth; } //获取当前阶段 public int getCurrentPart(){ return mCurrentPart; } }
//数据mode
public class DefaultPropBean { private float prop;//比例 private String msg; public DefaultPropBean(float prop, String msg){ this.prop = prop; this.msg = msg; } public float getProp() { return prop; } public void setProp(float prop) { this.prop = prop; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
//数据demo
Listlist = new ArrayList (); list.add(new DefaultBean(0.2f,"1111")); list.add(new DefaultBean(0.3f,"2222")); list.add(new DefaultBean(0.2f,"3333")); list.add(new DefaultBean(0.1f,"4444")); list.add(new DefaultBean(0.2f,"5555"));