开篇
继公交线路 VerticalStepView文章之后,我又亲自撸了
酷炫的Step View,本篇文章的分享希望能帮上童鞋们的忙。啥也不说了,先看效果。
- 支持序列号个性化显示
- 支持在左边显示(或右边显示)
- 序列号支持对齐顶部堆叠、对齐第一个序列号堆叠
效果截屏
立即体验
扫描以下二维码下载体验App(从0.2.3
版本开始,体验App内嵌版本更新检测功能):
JSCKit库传送门:https://github.com/JustinRoom/JSCKit
简析源码
VerticalStepLinearLayout.java:继承自LinearLayout
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
测量并计算序列号的中心位置。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int count = getChildCount();
//LinearLayout自带的分割线属性
Drawable drawable = null;
if (getShowDividers() == LinearLayout.SHOW_DIVIDER_MIDDLE) {
drawable = getDividerDrawable();
}
yAxis.clear();
float y = getPaddingTop();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
//child的上下margin
MarginLayoutParams params = (MarginLayoutParams) child.getLayoutParams();
y += params.topMargin + child.getMeasuredHeight() / 2.0f;
if (i == 0){
minToTop = getPaddingTop() + params.topMargin;
}
yAxis.put(i, y);
y += child.getMeasuredHeight() / 2.0f;
y += params.bottomMargin;
//考虑到LinearLayout自带的分割线属性
if (drawable != null) {
y += drawable.getIntrinsicHeight();
}
}
sortIndex(false);
}
private void sortIndex(boolean invalidate)
序列号堆叠,需重新计算其中心位置。
- 根据用户选择其中一种序列号堆叠方式:
//两种不同的序列号堆叠起始位置
private void sortIndex(boolean invalidate) {
switch (sortBase) {
case SORT_BASE_TOP:
sortIndexBaseOnTop();
break;
case SORT_BASE_FIRST:
sortIndexBaseOnFirst();
break;
}
if (invalidate)
invalidate();
}
- 1、从顶部开始堆叠:
private void sortIndexBaseOnTop() {
yShowAxis.clear();
float minDistance = indexRadius * 2 + 10;
for (int i = 0; i < yAxis.size(); i++) {
if (i == 0) {
yShowAxis.put(i, Math.max(minToTop + indexRadius + scrollY, yAxis.get(i)));
} else {
float pre = yShowAxis.get(yShowAxis.size() - 1);
if (yAxis.get(i) - pre < minDistance)
yShowAxis.put(i, pre + minDistance);
else
yShowAxis.put(i, yAxis.get(i));
}
}
}
- 2、从第一个序列号开始堆叠:
private void sortIndexBaseOnFirst() {
yShowAxis.clear();
float minDistance = indexRadius * 2 + 10;
yShowAxis.put(0, yAxis.get(0) + scrollY);
for (int i = 1; i < yAxis.size(); i++) {
float pre = yShowAxis.get(yShowAxis.size() - 1);
if (yAxis.get(i) - pre < minDistance)
yShowAxis.put(i, pre + minDistance);
else
yShowAxis.put(i, yAxis.get(i));
}
}
protected void onDraw(Canvas canvas)
开始绘制
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (yShowAxis.size() <= 1)
return;
float centerX = 0;
switch (location) {
case LEFT:
centerX = Math.max(getPaddingLeft() / 2.0f, indexRadius);
break;
case RIGHT:
centerX = getWidth() - Math.max(getPaddingRight() / 2.0f, indexRadius);
break;
}
//TODO draw the vertical line
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(1);
paint.setColor(lineColor);
drawLine(canvas, centerX);
//TODO draw circle
paint.setStyle(Paint.Style.FILL);
paint.setColor(indexColor);
textPaint.setColor(indexTextColor);
textPaint.setTextSize(indexTextSize);
Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
for (int i = 0; i < yShowAxis.size(); i++) {
drawIndex(canvas, i, centerX, fontMetrics);
}
}
扩展性
为了有一个良好的扩展性,我专门抽出两个绘制方法,重写以下两个方法可以绘制你自己的
style
风格。
- 绘制竖线
public void drawLine(@NonNull Canvas canvas, float centerX) - 绘制每一个序列号
public void drawIndex(@NonNull Canvas canvas, int index, float centerX, @NonNull Paint.FontMetrics fontMetrics)
结合ScrollView
使用
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initMenu();
setTitleBarTitle(getClass().getSimpleName().replace("Activity", ""));
int space = CompatResourceUtils.getDimensionPixelSize(this, R.dimen.space_16);
ScrollView lScrollView = new ScrollView(this);
stepLinearLayout = new VerticalStepLinearLayout(this);
stepLinearLayout.setPadding(space * 2, 0, space * 2, 0);
stepLinearLayout.setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE);
GradientDrawable lineSpaceDrawable = DynamicDrawableFactory.cornerRectangleDrawable(Color.TRANSPARENT, 0);
lineSpaceDrawable.setSize(-1, CompatResourceUtils.getDimensionPixelSize(this, R.dimen.space_8));
stepLinearLayout.setDividerDrawable(lineSpaceDrawable);
// stepLinearLayout.setDividerPadding(getResources().getDimensionPixelSize(R.dimen.space_16));
lScrollView.addView(stepLinearLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
setContentView(lScrollView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
lScrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
@Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
stepLinearLayout.updateScroll(v.getScrollY());
}
});
}
for (int i = 0; i < txts.length; i++) {
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.topMargin = space;
TextView textView = new TextView(this);
textView.setText(txts[I]);
stepLinearLayout.addView(textView, params);
}
}
- 关键代码:监听
ScrollView
的滑动,更新VerticalStepLinearLayout
的序列号位置
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
lScrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
@Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
stepLinearLayout.updateScroll(v.getScrollY());
}
});
}
童鞋们,又到文章结尾了,动动你们可爱的小手指点个吧。非常感谢!!!
篇尾
Wechat:eoy9527
。
不用相当的独立功夫,不论在哪个严重的问题上都不能找出真理;谁怕用功夫,谁就无法找到真理。 —— 列宁