出于项目需求与对自己的锻炼,自定义了步骤进度指示器,与大家分享,效果如图。
1.新建StepWidget控件类
public class StepWidget extends View {
int totalCount; //总步骤数量
int arrowWidth; //箭头的宽度
int defaultBackColor; //默认的背景颜色值
int selectedBackColor; //进度达到时的背景颜色值
int defaultTextColor; //进度达到时的背景颜色值
int selectedTextColor; //进度到达时的字体颜色值
int gapColor; //步骤间的空隙颜色
float textSize; //字体大小
float gapWidth; //步骤空隙大小
boolean hasGap = true; //是否有空隙
Paint paint;
Paint.FontMetrics fm;
Rect rect;
Path path;
int currentIndex = 1;
int width; //空间测量宽度
int height; //空间测量高度
public StepWidget(Context context) {
this(context, null);
}
public StepWidget(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public StepWidget(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.StepWidget, defStyleAttr, 0);
totalCount = ta.getInteger(R.styleable.StepWidget_totalCount, 3);
arrowWidth = ta.getDimensionPixelOffset(R.styleable.StepWidget_arrowWidth, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, context.getResources().getDisplayMetrics()));
defaultBackColor = context.getResources().getColor(ta.getResourceId(R.styleable.StepWidget_defaultBackColor, R.color.color_d8d8d8));
selectedBackColor = context.getResources().getColor(ta.getResourceId(R.styleable.StepWidget_selectedBackColor, R.color.color_4c4c4e));
defaultTextColor = context.getResources().getColor(ta.getResourceId(R.styleable.StepWidget_defaultTextColor, R.color.color_4c4c4e));
selectedTextColor = context.getResources().getColor(ta.getResourceId(R.styleable.StepWidget_selectedTextColor, R.color.white));
textSize = ta.getDimensionPixelSize(R.styleable.StepWidget_android_textSize, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, context.getResources().getDisplayMetrics()));
gapWidth = ta.getDimensionPixelSize(R.styleable.StepWidget_gapWidth, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, 1, context.getResources().getDisplayMetrics()));
gapColor = context.getResources().getColor(ta.getResourceId(R.styleable.StepWidget_gapColor, R.color.white));
hasGap = ta.getBoolean(R.styleable.StepWidget_hasGap, true);
ta.recycle();
paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(selectedBackColor);
String text = "Step 2";
rect = new Rect();
paint.setTextSize(textSize);
paint.setAntiAlias(true);
paint.getTextBounds(text, 0, text.length(), rect);
path = new Path();
fm = paint.getFontMetrics();
if (hasGap)
paint.setStrokeWidth(gapWidth);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = getMeasuredWidth();
height = getMeasuredHeight();
}
@Override
protected void onDraw(Canvas canvas) {
int avgWidth = width / totalCount; //根据总步骤数获取平均宽度(ps:别太大,不好看的)
int selectedWidth = avgWidth * currentIndex; //根据当前步骤currentIndex确定箭头的宽度
if (currentIndex == totalCount) {
canvas.drawColor(selectedBackColor);
} else {
canvas.drawColor(defaultBackColor);
path.reset(); //Clear the previous setting, make path empty
path.moveTo(0, 0);
path.lineTo(selectedWidth - arrowWidth, 0);
path.lineTo(selectedWidth, height / 2);
path.lineTo(selectedWidth - arrowWidth, height);
path.lineTo(0, height);
paint.setColor(selectedBackColor);
canvas.drawPath(path, paint);
}
for (int i = 1; i <= totalCount; i++) {
if (i <= currentIndex) {
paint.setColor(selectedTextColor);
canvas.drawText("Step " + i, (avgWidth - rect.width()) / 2 + avgWidth * (i - 1), height - (height - rect.height()) / 2 - fm.descent, paint);
} else {
paint.setColor(defaultTextColor);
canvas.drawText("Step " + i, (avgWidth - rect.width()) / 2 + avgWidth * (i - 1), height - (height - rect.height()) / 2 - fm.descent, paint);
}
if (hasGap) {
if (i < currentIndex || (i > currentIndex && i != totalCount)) {
paint.setColor(gapColor);
canvas.drawLine(avgWidth * i, 0, avgWidth * i, height, paint);
}
}
}
}
public void previous() {
if (currentIndex > 1) {
currentIndex--;
invalidate();
if (onStepChangedListener != null) onStepChangedListener.onStepChanged(currentIndex);
}
}
public void next() {
if (currentIndex < totalCount) {
currentIndex++;
invalidate();
if (onStepChangedListener != null) onStepChangedListener.onStepChanged(currentIndex);
}
}
public int getCurrentIndex() {
return currentIndex;
}
private OnStepChangedListener onStepChangedListener; //步骤变化监听回调,根据需要添加,如果不为null,会在改变之后自动调用
public interface OnStepChangedListener {
void onStepChanged(int currentStep);
}
public void setOnStepChangedListener(OnStepChangedListener onStepChangedListener) {
this.onStepChangedListener = onStepChangedListener;
}
}
3.在布局文件中引用,比如
if (currentIndex == totalCount) {
canvas.drawColor(selectedBackColor);
} else {
canvas.drawColor(defaultBackColor);
path.reset(); //Clear the previous setting, make path empty
path.moveTo(0, 0);
path.lineTo(selectedWidth - arrowWidth, 0);
path.lineTo(selectedWidth, height / 2);
path.lineTo(selectedWidth - arrowWidth, height);
path.lineTo(0, height);
paint.setColor(selectedBackColor);
canvas.drawPath(path, paint);
}
for (int i = 1; i <= totalCount; i++) {
if (i <= currentIndex) {
paint.setColor(selectedTextColor);
canvas.drawText("Step " + i, (avgWidth - rect.width()) / 2 + avgWidth * (i - 1), height - (height - rect.height()) / 2 - fm.descent, paint);
} else {
paint.setColor(defaultTextColor);
canvas.drawText("Step " + i, (avgWidth - rect.width()) / 2 + avgWidth * (i - 1), height - (height - rect.height()) / 2 - fm.descent, paint);
}
if (hasGap) {
if (i < currentIndex || (i > currentIndex && i != totalCount)) {
paint.setColor(gapColor);
canvas.drawLine(avgWidth * i, 0, avgWidth * i, height, paint);
}
}
}