Android 超级酷炫的Step View,看了不后悔

开篇

  继公交线路 VerticalStepView文章之后,我又亲自撸了
酷炫的Step View,本篇文章的分享希望能帮上童鞋们的忙。啥也不说了,先看效果。

  • 支持序列号个性化显示
  • 支持在左边显示(或右边显示)
  • 序列号支持对齐顶部堆叠、对齐第一个序列号堆叠

效果截屏

Android 超级酷炫的Step View,看了不后悔_第1张图片
photo 1

Android 超级酷炫的Step View,看了不后悔_第2张图片
photo 2

Android 超级酷炫的Step View,看了不后悔_第3张图片
photo 3

立即体验

扫描以下二维码下载体验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

不用相当的独立功夫,不论在哪个严重的问题上都不能找出真理;谁怕用功夫,谁就无法找到真理。 —— 列宁

你可能感兴趣的:(Android 超级酷炫的Step View,看了不后悔)