美文网首页Android 进阶技术篇专题我爱编程Android自定义View
Android 超级酷炫的Step View,不看你会后悔

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

作者: SwitchLife | 来源:发表于2018-08-02 15:57 被阅读16次

    开篇

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

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

    效果截屏

    photo 1
    photo 2
    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,不看你会后悔

        本文链接:https://www.haomeiwen.com/subject/tqijvftx.html