一、先看看效果,是不是你需要的
二 、使用方式
StepHorizontalView mStepSv = (StepHorizontalView) findViewById(R.id.sv_step);
mStepSv.setProgress(3, 4);
List list = new ArrayList<>();
list.add("第一步");
list.add("第二步");
list.add("第三步");
list.add("第四步");
mStepSv.setTitles(list);
三、布局
四、属性讲解
1. h_bg_color 默认进度条的颜色
2. h_bg_radius 默认节点的半径大小
3. h_bg_width 默认间隔线的宽度
4. h_pro_color 已过进度条的颜色
5. h_pro_radius 已过节点的半径大小
6. h_pro_width 已过间隔线的宽度
7. h_text_padding 进度条与文本的距离
8. h_textsize 文本的字体大小
9. h_max_step 最多节点的个数
10. h_pro_step 节点的进度
五、自定义控件
public class StepHorizontalView extends View {
private int bgWidth;
private int bgHeight;
private float bgRadius;
private float proRadius;
private float startX;
private float stopX;
private float bgCenterY;
private int lineBgWidth;
private int bgColor;
private int lineProWidth;
private int proColor;
private int textPadding;
private int maxStep;
private int textSize;
private int proStep;
private Paint bgPaint;
private Paint proPaint;
private int interval;
private List titles;
private Map map;
private float startLine;
private float stopLine;
public StepHorizontalView(Context context) {
this(context, null);
}
public StepHorizontalView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public StepHorizontalView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.FlowViewHorizontal);
bgRadius = ta.getDimension(R.styleable.FlowViewHorizontal_h_bg_radius, 10);
proRadius = ta.getDimension(R.styleable.FlowViewHorizontal_h_pro_radius, 8);
lineBgWidth = (int) ta.getDimension(R.styleable.FlowViewHorizontal_h_bg_width, 3f);
bgColor = ta.getColor(R.styleable.FlowViewHorizontal_h_bg_color, Color.parseColor("#cccccc"));
lineProWidth = (int) ta.getDimension(R.styleable.FlowViewHorizontal_h_pro_width, 2f);
proColor = ta.getColor(R.styleable.FlowViewHorizontal_h_pro_color, Color.parseColor("#EF5350"));
textPadding = (int) ta.getDimension(R.styleable.FlowViewHorizontal_h_text_padding, 20);
maxStep = ta.getInt(R.styleable.FlowViewHorizontal_h_max_step, 6);
textSize = (int) ta.getDimension(R.styleable.FlowViewHorizontal_h_textsize, 20);
proStep = ta.getInt(R.styleable.FlowViewHorizontal_h_pro_step, 1);
ta.recycle();
initView();
}
private void initView() {
bgPaint = new Paint();
bgPaint.setAntiAlias(true); // 锯齿
bgPaint.setStyle(Paint.Style.FILL);
bgPaint.setColor(bgColor);
bgPaint.setStrokeWidth(lineBgWidth);
bgPaint.setTextSize(textSize);
bgPaint.setTextAlign(Paint.Align.CENTER);
proPaint = new Paint();
proPaint.setAntiAlias(true);
proPaint.setStyle(Paint.Style.FILL);
proPaint.setColor(proColor);
proPaint.setStrokeWidth(lineProWidth);
proPaint.setTextSize(textSize);
proPaint.setTextAlign(Paint.Align.CENTER);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthMode == MeasureSpec.EXACTLY) {
bgWidth = widthSize;
}
if (heightMode == MeasureSpec.EXACTLY) {
bgHeight = heightSize;
}
interval = (int) ((bgWidth-bgRadius*2-getPaddingRight()-getPaddingLeft())/(maxStep - 1));//紧挨着的两个圆心的距离
startLine = getPaddingLeft() + bgRadius * 2;//作为线的起点
stopLine = getPaddingLeft() + interval * (maxStep-1);//作为线的终点
startX = getPaddingLeft() + bgRadius;//作为圆的起始点
stopX = stopLine + bgRadius;//作为最后一个圆的圆心 bgWidth - bgRadius - getPaddingRight()
bgCenterY = getPaddingTop()+bgRadius;//作为线和圆心的纵坐标
}
@Override
protected void onDraw(Canvas canvas) {
drawBg(canvas);
drawProgress(canvas);
drawText(canvas);
}
/**
* 绘画文本
* @param canvas
*/
private void drawText(Canvas canvas) {
for (int i = 0; i < maxStep; i++) {
if (i < proStep) {
if (null != titles && i < titles.size()) {
canvas.drawText(titles.get(i), startX + (i * interval), bgCenterY + textPadding + (bgRadius < proRadius ? proRadius : bgRadius), proPaint);
}
} else {
if (null != titles && i < titles.size()) {
String title = titles.get(i);
if (null == title) {
continue;
}
canvas.drawText(title, startX + (i * interval), bgCenterY + textPadding + (bgRadius < proRadius ? proRadius : bgRadius), bgPaint);
}
}
}
}
/**
* 绘画底部默认进度条
* @param canvas
*/
private void drawBg(Canvas canvas) {
canvas.drawLine(startLine, bgCenterY, stopLine, bgCenterY, bgPaint);
for (int i = 0; i < maxStep; i++) {
canvas.drawCircle(startX + (i * interval), bgCenterY, bgRadius, bgPaint);
}
}
/**
* 绘画进度
* @param canvas
*/
private void drawProgress(Canvas canvas) {
for (int i = 0; i < proStep; i++) {
canvas.drawCircle(startX + (i * interval), bgCenterY, proRadius, proPaint);
canvas.drawLine(startX, bgCenterY, startX + (i * interval), bgCenterY, proPaint);
}
}
/**
* 进度设置
*
* @param progress 已完成到哪部
* @param maxStep 总步骤
*/
public void setProgress(int progress, int maxStep) {
proStep = progress;
this.maxStep = maxStep;
invalidate();
}
public void setTitles(List titles){
this.titles = titles;
}
}
六、在values中创建一个attrs.xml文件
七、不足之处
这个控件不能wrap_content,但不会报错,只是效果和match_parent一样,所以尽量写明具体高度。
若有问题,请大家多多指正。