Android自定義View實現流程節點圖

項目需要,需要做一個自上而下的流程節點圖,實現過程如下,當然不是最終實現效果;
在這裏插入圖片描述

  • 自定義屬性

首選在values文件下建一個attrs文件,內容如下

<resources>
    <declare-styleable name="ProcessView">
        <attr name="itemColor" format="color" />
        <attr name="verticalNum" format="integer" />
        <attr name="horizontalNum" format="string" />
        <attr name="itemWidth" format="dimension" />
        <attr name="itemHeight" format="dimension" />
        <attr name="itemTextSize" format="dimension" />
        <attr name="itemVerticalSpace" format="dimension" />
        <attr name="itemHorizontalSpace" format="dimension" />
    </declare-styleable>
</resources>
  • 選擇和設置構造方法;

然後自定義的ProcessView 繼承view

  public ProcessView(Context context) {
        this(context, null);
    }

    public ProcessView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(attrs);//初始化自定義屬性
    }

  • 重寫onMeasure()方法
  @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(View.MeasureSpec.getSize(widthMeasureSpec), measureSize(1));
    }
  • 重寫onDraw()方法
 @Override
    public void onDraw(Canvas canvas) {
        for (int vIndex = 0; vIndex < verticalNum; vIndex++) {
            List<Rect> list = new ArrayList<>();
            int hNum = Integer.parseInt(horizontalNum[vIndex]);
            // item實際寬度
            int tempWidth = (getWidth() - horizontalSpace * (hNum - 1)) / hNum;

            for (int hIndex = 0; hIndex < hNum; hIndex++) {
                Rect rectBorder = new Rect();
                String str = texts.get(vIndex).get(hIndex);
                rectBorder.top = (vIndex) * itemHeight + (vIndex) * verticalSpace;
                rectBorder.bottom = rectBorder.top + itemHeight;
                if (tempWidth >= itemWidth) {
                    // 距離兩邊的距離
                    int margin = (getWidth() - (itemWidth * hNum + (hNum - 1) * horizontalSpace)) / 2;
                    rectBorder.left = margin + hIndex * itemWidth + hIndex * horizontalSpace;
                    rectBorder.right = itemWidth + rectBorder.left;
                } else {
                    rectBorder.left = hIndex * tempWidth + hIndex * horizontalSpace;
                    rectBorder.right = tempWidth + rectBorder.left;
                }
                drawContent(canvas, rectBorder, str);
                drawLinkLine(canvas, rectBorder, hNum, vIndex);
                list.add(rectBorder);
            }
            rects.put(vIndex, list);
        }
    }
  • 文字內容

  public HashMap<Integer, List<String>> getTextShow() {
        List<String> text1 = Arrays.asList("執行通知");
        List<String> text2 = Arrays.asList("送達文書");
        List<String> text3 = Arrays.asList("強行措施", "財產調查", "解除措施");
        List<String> text4 = Arrays.asList("查詢存款", "搜查", "傳喚", "懸賞執行");
        List<String> text5 = Arrays.asList("查明財產");
        List<String> text6 = Arrays.asList("查封", "扣押", "凍結", "扣劃", "評估", "拍賣");
        List<String> text7 = Arrays.asList("執行和解", "終本約談", "自動履行");
        HashMap<Integer, List<String>> map = new HashMap<Integer, List<String>>();
        map.put(0, text1);
        map.put(1, text2);
        map.put(2, text3);
        map.put(3, text4);
        map.put(4, text5);
        map.put(5, text6);
        map.put(6, text7);
        return map;
    }
  • 畫文字
 /**
     * 畫文字和背景
     */
    private void drawContent(Canvas canvas, Rect rect, String str) {
        canvas.drawRect(rect, paint);
        canvas.drawText(str
                , (rect.right + rect.left) / 2f
                , (rect.bottom + rect.top) / 2f + textHeight / 2 - paint.getFontMetrics().descent
                , paint);
    }
  • 畫連線
/***
     * 畫連接線
     * @param rect     當前Item的Rect
     * @param currHNum 當前的水平方向 有多少個Item
     * @param vIndex 當前是垂直方向的第幾個
     */
    private void drawLinkLine(Canvas canvas, Rect rect, int currHNum, int vIndex) {
        int stopX = getX(rect);
        int startX = getX(rect);

        if (vIndex < verticalNum - 1) {
            //畫Item下面一半的垂直連接線
            canvas.drawLine(startX, rect.bottom, stopX, (rect.bottom + verticalSpace / 2f), paint);

            //畫水平連接線
            if (currHNum > 1 && lastItemRect != null && lastItemRect.top == rect.top) {
                canvas.drawLine(getX(lastItemRect), (rect.bottom + verticalSpace / 2f), getX(rect), (rect.bottom + verticalSpace / 2f), paint);
            }
        }

        if (vIndex != 0) {
            //畫Item上面一半的垂直連接線
            canvas.drawLine(startX, (rect.top - verticalSpace / 2f), stopX, rect.top, paint);

            //畫水平連接線
            if (currHNum > 1 && lastItemRect != null && lastItemRect.top == rect.top) {
                canvas.drawLine(getX(lastItemRect), (rect.top - verticalSpace / 2f), getX(rect), (rect.top - verticalSpace / 2f), paint);
            }
        }
        lastItemRect = rect;
    }
  • 佈局文件
 <com.example.test.shundemo.ProcessView1
        android:layout_marginTop="17dp"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="16dp"
        android:layout_marginBottom="51dp"
        android:id="@+id/process_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:horizontalNum="1,1,3,4,1,6,3"
        app:itemColor="#303030"
        app:itemHeight="35dp"
        app:itemHorizontalSpace="15dp"
        app:itemTextSize="14dp"
        app:itemVerticalSpace="45dp"
        app:itemWidth="80dp"
        app:verticalNum="7" />

更多效果圖見下
在這裏插入圖片描述
在這裏插入圖片描述
Demo地址https://github.com/shunplus/ProcessView

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章