最近遇到一个按步骤走流程的需求,相信其他的程序员也会遇到这样的需求吧,好了下面说一下我解决这个问题的过程
刚接到这个需求的时候,我是使用布局的方式画的,很长很乱,适配是发现,那是相当的烂啊,根本无法满足适配的需要,无语啊。代码就不贴了哈。
还是转换思路,自己写吧,于是就简单的写一个。代码如下:
思路如下:
先写出7个方法,每个方法实现的是每个步骤的状态,画出圆点、连线、每个步骤的名称
import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.view.View; public class StepView extends View { private int mWidth;//view的总宽度 private Bitmap curImage;//当前步骤图片 private Bitmap passedImage;//已完成步骤图片 private Bitmap unPassImage;//未完成步骤图片 private Paint paint;//画bitmap使用的画笔 private Paint linePaint;//画线使用的画笔 private float lineWidth;//步骤之间每根线的长度 private int lineCount = 6;//共多少条连线 /** * 当前图片与未完成和完成图片大小不一致 * 且图片要在一条直线上,因此,画完成和未完成 * 的图片时要计算出marginTop */ private float unpassTop = 0; private Paint textPait;//画文字时需要的画笔 private int curIndex = 0;//当前步骤 private int marginTop = 40;//文字与图片之间的间距 public StepView(Context context) { super(context); init(); } public StepView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } public StepView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init(){ //初始化图片 curImage = BitmapFactory.decodeResource(getResources(), R.drawable.process_current); passedImage = BitmapFactory.decodeResource(getResources(), R.drawable.process_passed); unPassImage = BitmapFactory.decodeResource(getResources(), R.drawable.process_unpass); //初始化画笔 paint = new Paint(); linePaint = new Paint(); linePaint.setAntiAlias(true); linePaint.setStrokeWidth(5); linePaint.setColor(Color.parseColor("#cfcfcf")); textPait = new Paint(); textPait.setAntiAlias(true); textPait.setTextSize(36); textPait.setColor(Color.parseColor("#eeaa2f")); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); //设置宽度,随着view的宽度的变化而变化 this.mWidth = w; //计算步骤之间线条的长度 lineWidth = (float)(mWidth - passedImage.getWidth() * lineCount - curImage.getWidth()) / lineCount; //计算完成与未完成图片与View顶部的间距 unpassTop = (curImage.getHeight() - unPassImage.getHeight()) / 2; }@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); float startX = 0; for(int i = 0; i<= lineCount; i++){ //先画点,当前步骤之前为已完成,当前步骤之后为未完成 if(curIndex > i){ drawCircleBitmap(canvas,startX,passedImage,unpassTop); }else if(curIndex == i){ drawCircleBitmap(canvas,startX,curImage,0); }else{ drawCircleBitmap(canvas,startX,unPassImage,unpassTop); } //画文字 drawText(i,canvas,startX,curIndex); //画线条 if(curIndex > i){ //计算新的起始位置 startX += passedImage.getWidth(); drawLine(canvas,startX,Color.parseColor("#eeaa2f")); }else if(curIndex == i){ if(i != 6){ //计算新的起始位置 startX += curImage.getWidth(); drawLine(canvas,startX,Color.parseColor("#cfcfcf")); } }else{ if(i != 6){ //计算新的起始位置 startX += unPassImage.getWidth(); drawLine(canvas,startX,Color.parseColor("#cfcfcf")); } } //计算新的起始位置 startX += lineWidth; } } private void drawCircleBitmap(Canvas canvas,float startX,Bitmap bitmap,float marginTop){ canvas.drawBitmap(bitmap,startX,marginTop,paint); } private void drawLine(Canvas canvas,float startX,int color){ linePaint.setColor(color); canvas.drawLine(startX,curImage.getHeight() / 2,startX + lineWidth,curImage.getHeight() / 2,linePaint); } private void drawText(int index,Canvas canvas,float startX,int curIndex){ if(index <= curIndex){ textPait.setColor(Color.parseColor("#eeaa2f")); }else{ textPait.setColor(Color.parseColor("#cfcfcf")); } if(index == 0){ canvas.drawText("第一步",0,curImage.getHeight() + marginTop,textPait); }else if(index == 1){ if(curIndex == 1){ canvas.drawText("第二步",startX - 25,curImage.getHeight() + marginTop,textPait); }else{ canvas.drawText("第二步",startX - 35,curImage.getHeight() + marginTop,textPait); } }else if(index == 2){ if(curIndex == 2){ canvas.drawText("第三步",startX - 25,curImage.getHeight() + marginTop,textPait); }else{ canvas.drawText("第三步",startX - 35,curImage.getHeight() + marginTop,textPait); } }else if(index == 3){ if(curIndex == 3){ canvas.drawText("第四步",startX - 25,curImage.getHeight() + marginTop,textPait); }else{ canvas.drawText("第四步",startX - 35,curImage.getHeight() + marginTop,textPait); } }else if(index == 4){ if(curIndex == 4){ canvas.drawText("第五步",startX - 25,curImage.getHeight() + marginTop,textPait); }else{ canvas.drawText("第五步",startX - 35,curImage.getHeight() + marginTop,textPait); } }else if(index == 5){ if(curIndex == 5){ canvas.drawText("第六步",startX - 25,curImage.getHeight() + marginTop,textPait); }else{ canvas.drawText("第六步",startX - 35,curImage.getHeight() + marginTop,textPait); } }else if(index == 6){ canvas.drawText("第七步",mWidth - 90,curImage.getHeight() + marginTop,textPait); } }
public void setCurIndex(int curIndex) { this.curIndex = curIndex; invalidate(); } }
以上的代码是有缺陷,当文字大小改变后,产生的问题需要重新计算,这对适配来说是非常痛苦的,在使用过程中发现了这个问题,故对比做了进一步的优化。
public class StepView extends View { private int mWidth;//view的总宽度 private Bitmap curImage;//当前步骤图片 private Bitmap passedImage;//已完成步骤图片 private Bitmap unPassImage;//未完成步骤图片 private Paint paint;//画bitmap使用的画笔 private Paint linePaint;//画线使用的画笔 private float lineWidth;//步骤之间每根线的长度 private int lineCount = 0;//共多少条连线 /** * 当前图片与未完成和完成图片大小不一致 * 且图片要在一条直线上,因此,画完成和未完成 * 的图片时要计算出marginTop */ private float unpassTop = 0; private Paint textPait;//画文字时需要的画笔 private int curIndex = 0;//当前步骤 private int marginTop = 15;//文字与图片之间的间距 private int textSize = 12;//文字大小 private int passedImageWidth; private int curImageWidth; private int unpassImageWidth; private int startTextY; private String[] texts = {"第一步", "第二步", "第三步", "第四步", "第五步", "第六步", "第七步"}; private float[] textLengths = new float[7]; public StepView(Context context) { super(context); init(context); } public StepView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } public StepView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } private void init(Context context) { //初始化图片 curImage = BitmapFactory.decodeResource(getResources(), R.drawable.process_current); passedImage = BitmapFactory.decodeResource(getResources(), R.drawable.process_passed); unPassImage = BitmapFactory.decodeResource(getResources(), R.drawable.process_unpass); textSize = dip2px(context, textSize); marginTop = dip2px(context, marginTop); lineCount = texts.length - 1; passedImageWidth = passedImage.getWidth(); curImageWidth = curImage.getWidth(); unpassImageWidth = unPassImage.getWidth(); startTextY = curImage.getHeight() + marginTop; //初始化画笔 paint = new Paint(); linePaint = new Paint(); linePaint.setAntiAlias(true); linePaint.setStrokeWidth(5); linePaint.setColor(Color.parseColor("#cfcfcf")); textPait = new Paint(); textPait.setAntiAlias(true); textPait.setTextSize(textSize); textPait.setColor(Color.parseColor("#eeaa2f")); for (int i = 0, len = texts.length; i < len; i++) { textLengths[i] = getTextLength(texts[i]); } } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); //设置宽度,随着view的宽度的变化而变化 this.mWidth = w; //计算步骤之间线条的长度 lineWidth = (float) (mWidth - passedImageWidth * lineCount - curImageWidth) / lineCount; //计算完成与未完成图片与View顶部的间距 unpassTop = (curImage.getHeight() - unPassImage.getHeight()) / 2; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); float startX = 0; for (int i = 0; i <= lineCount; i++) { //先画点,当前步骤之前为已完成,当前步骤之后为未完成 if (curIndex > i) { drawCircleBitmap(canvas, startX, passedImage, unpassTop); } else if (curIndex == i) { drawCircleBitmap(canvas, startX, curImage, 0); } else { drawCircleBitmap(canvas, startX, unPassImage, unpassTop); } //画文字 drawText(i, canvas, startX, curIndex, curIndex == i); //画线条 if (curIndex > i) { //计算新的起始位置 startX += passedImageWidth; drawLine(canvas, startX, Color.parseColor("#eeaa2f")); } else if (curIndex == i) { if (i != 6) { //计算新的起始位置 startX += curImageWidth; drawLine(canvas, startX, Color.parseColor("#cfcfcf")); } } else { if (i != 6) { //计算新的起始位置 startX += unpassImageWidth; drawLine(canvas, startX, Color.parseColor("#cfcfcf")); } } //计算新的起始位置 startX += lineWidth; } } private void drawCircleBitmap(Canvas canvas, float startX, Bitmap bitmap, float marginTop) { canvas.drawBitmap(bitmap, startX, marginTop, paint); } private void drawLine(Canvas canvas, float startX, int color) { linePaint.setColor(color); canvas.drawLine(startX, curImage.getHeight() / 2, startX + lineWidth, curImage.getHeight() / 2, linePaint); } private void drawText(int index, Canvas canvas, float startX, int curIndex, boolean isCur) { int div = isCur ? curImageWidth / 2 : passedImageWidth / 2; if (index <= curIndex) { textPait.setColor(Color.parseColor("#eeaa2f")); } else { textPait.setColor(Color.parseColor("#cfcfcf")); } if (index == 0) { canvas.drawText(texts[0], 0, startTextY, textPait); } else if (index == texts.length - 1) { canvas.drawText(texts[texts.length - 1], mWidth - textLengths[index], startTextY, textPait); } else { canvas.drawText(texts[index], startX + div - textLengths[index] / 2, startTextY, textPait); } } public void setCurIndex(int curIndex) { this.curIndex = curIndex; invalidate(); } private float getTextLength(String text) { // 使用panit获取文字的宽度 float textLength = textPait.measureText(text); return textLength; } /** * dip 2 px * * @param context * @param dipValue * @return 上午11:37:12 */ private int dip2px(Context context, int dipValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dipValue * scale); } }
以上就是全部的代码实现,初步的封装了步骤的变化,其实还可以进一步封装,比如自定义属性,步骤总数、步骤标题集合,已完成步骤的颜色、当前步骤颜色、未完成步骤颜色等等,希望有兴趣的同学进行进一步的封装
需要的图片资源已经上传,本想着把第一步即每个步骤为一个方法实现的代码贴出来的,实在是太麻烦啦,就算啦。
欢迎各位指正!