实现竖直的步骤进度条,先看效果:
QQ截图20160527173654.png
可以看到,实现的主要难点在于步骤条的线的高度是要跟右边的布局保持一致的,而右边的布局的高度是不定的,也就是用 wrap_content,
所以如果左边线高度使用 match_parent 的话就会撑到满屏。
所有解决方法就是,定义一个 ViewGroup 包着左边的线和右边的布局,然后获取这个 ViewGroup 的高度作为左边的线的高度。
这里的 ViewGroup 我选择继承 LinearLayout ,也可以继承其他。
看代码:
public class ProLinearLayout extends LinearLayout {
private ProLine mProLine; //左边的进度条
//线的类型,实线还是虚线
public final static String typeSolid = "solid";
public final static String typeDotted = "dotted";
//是否是第一个或者是最后一个线
private boolean isLastOne = false;
private boolean isTopOne = false;
//最上面的一个的线是不是虚线
private boolean isTopTypeDotted = false;
private String lineType = typeSolid;
//那个圈的图片,也可以自己画,我这里就用图片
private Bitmap imgBitmap;
public ProLinearLayout(Context context) {
super(context);
init();
}
public ProLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
LayoutParams lp;
private void init() {
imgBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pro_readed);
//将线添加到 LinearLayout 的左边,并设置一些边距,这里注意一点就是 LayoutParams 第二个参数,如果平时正常情况,
//可以使用 LayoutParams.WRAP_CONTENT,但如果外层有使用 ScrollView ,就要使用 LayoutParams.MATCH_PARENT,
//不然控件就会展不开,就会不显示。
mProLine = new ProLine(getContext());
lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
lp.rightMargin = todp(14);
lp.leftMargin = todp(16);
this.addView(mProLine, lp);
}
public ProLinearLayout setLineType(String lineType) {
this.lineType = lineType;
return this;
}
public ProLinearLayout setImageResources(int resId) {
this.imgBitmap = BitmapFactory.decodeResource(getResources(), resId);
return this;
}
public ProLinearLayout setIsLastOne(boolean isLastOne) {
this.isLastOne = isLastOne;
return this;
}
public ProLinearLayout setIsTopTypeDotted(boolean isTopTypeDotted) {
this.isTopTypeDotted = isTopTypeDotted;
return this;
}
public ProLinearLayout setIsTopOne(boolean isTopOne) {
this.isTopOne = isTopOne;
return this;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mProLine.setParentHeight(getMeasuredHeight()); //将 LinearLayout 的高度设置成左边线的高度
mProLine.setLineType(lineType).setImageBitmap(imgBitmap)
.setIsLastOne(isLastOne).setIsTopOne(isTopOne).setIsTopTypeDotted(isTopTypeDotted);
}
private int todp(int px) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, px, getResources().getDisplayMetrics());
}
}
下面看左边线的代码:
public class ProLine extends View {
private Paint mPaint;
private Path path;
private PathEffect effects;
public final static String typeSolid = "solid";
public final static String typeDotted = "dotted";
private boolean isLastOne = false;
private boolean isTopOne = false;
private boolean isTopTypeDotted = false;
private String lineType = typeSolid;
private Bitmap imgBitmap;
private int mParentHeight = 0;
public ProLine(Context context) {
super(context);
init();
}
public ProLine(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
mPaint = new Paint();
path = new Path();
effects = new DashPathEffect(new float[] { 5, 5, 5, 5 }, 1);
mPaint.setColor(Color.parseColor("#979797"));
imgBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pro_readed);
}
public ProLine setLineType(String lineType) {
this.lineType = lineType;
return this;
}
public ProLine setImageBitmap(Bitmap bitmap) {
this.imgBitmap = bitmap;
return this;
}
public ProLine setIsLastOne(boolean isLastOne) {
this.isLastOne = isLastOne;
return this;
}
public void setParentHeight(int mParentHeight) {
this.mParentHeight = mParentHeight;
setMeasuredDimension(imgBitmap.getWidth(), this.mParentHeight); //这里再设置一次是因为如果布局动态改变(例如有个控件从隐藏到
显示状态)时,左边的线条高度不会变,还是原来的,原因是 onMeasure 方法不调用,所有无奈在这再写一次,不知道怎么改。
}
public ProLine setIsTopTypeDotted(boolean isTopTypeDotted) {
this.isTopTypeDotted = isTopTypeDotted;
return this;
}
public ProLine setIsTopOne(boolean isTopOne) {
this.isTopOne = isTopOne;
return this;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(imgBitmap.getWidth(), mParentHeight); // 测量高度等于外层 LinearLayout 高度
} else if (widthSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(imgBitmap.getWidth(), heightSpecSize);
} else if (heightSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(widthSpecSize, mParentHeight); // 测量高度等于外层 LinearLayout 高度
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 下面是各种判断和各种画图
float startX = imgBitmap.getWidth() / 2;
float stopX = startX;
float startY = imgBitmap.getHeight();
float stopY = mParentHeight;
int paddingTop = todp(12);
if (!isLastOne) {
canvas.drawBitmap(imgBitmap, 0, paddingTop, mPaint);
if (isTopOne) {
canvas.drawLine(startX, startY, stopX, stopY, mPaint);
} else {
if (isTopTypeDotted && lineType.equals(typeSolid)) {
drawDottedLine(canvas, startX, 0, startX, paddingTop);
canvas.drawLine(startX, startY, stopX, stopY, mPaint);
}
if (!isTopTypeDotted && lineType.equals(typeSolid)) {
canvas.drawLine(startX, 0, stopX, paddingTop, mPaint);
canvas.drawLine(startX, startY, stopX, stopY, mPaint);
}
if (isTopTypeDotted && lineType.equals(typeDotted)) {
drawDottedLine(canvas, startX, 0, startX, paddingTop);
drawDottedLine(canvas, startX, startY, stopX, stopY);
}
if (!isTopTypeDotted && lineType.equals(typeDotted)) {
canvas.drawLine(startX, 0, stopX, paddingTop, mPaint);
drawDottedLine(canvas, startX, startY, stopX, stopY);
}
}
} else {
canvas.drawBitmap(imgBitmap, 0, stopY - startY - paddingTop, mPaint);
if (lineType.equals(typeSolid)) {
canvas.drawLine(startX, 0, stopX, stopY - startY - paddingTop, mPaint);
} else if (lineType.equals(typeDotted)) {
drawDottedLine(canvas, startX, 0, stopX, stopY - startY - paddingTop);
}
}
}
private void drawDottedLine(Canvas canvas, float startX, float startY, float stopX, float stopY) {
mPaint.setStyle(Paint.Style.STROKE);
path.moveTo(startX, startY);
path.lineTo(stopX, stopY);
mPaint.setPathEffect(effects);
canvas.drawPath(path, mPaint);
}
private int todp(int px) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, px, getResources().getDisplayMetrics());
}
用法:
<com.text.lzx.ProLinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</com.text.lzx.ProLinearLayout>
java 代码中要设置的话就各种 set 方法就行。