Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android樹形控件繪制方法

Android樹形控件繪制方法

編輯:關於Android編程

前言

作為一個開發者,日常會接觸到很多優秀的軟件,其實,或多或少會有這樣的想法,我能不能開發一個自己軟件,甚至辦公軟件都希望是Markdown的文本,為何用office?我常常想自己做一個IDE什麼的。但是,很多只是想了一下就過了,一直沒有實現.
我接觸思維導圖軟件已經很久的了,開始是使用微軟的思維導圖軟件,接著XMind,後來使用了MindMaple Lite。感覺很好用的。也想過如何去實現一個思維導圖的軟件,加之我特別注意軟件的快捷鍵,我選取軟件常常是,看快捷如何,快捷鍵差的就不要了。基於自己的實踐使用思維導圖。前一個月我就在github上實現了一個樹形圖的Android控件,這個其實是我想實現思維導圖的開始。實現後,才發現並沒有多大的障礙。下面我就說說我如何打造一個樹形控件的。先上效果:


效果1


效果2

實現

一步一步可奪城。將自己要實現的東西肢解,那些實現得了的?那些未知的?

思路步驟概要

整個結構分為:樹形,節點; 對於Android的結構有:模型(樹形,節點),View;

  1. 實現樹形的節點node 的Model;
  2. 實現樹形Model;
  3. 實現View的繪制:1.添加View;2.確定Nodes的位置;3.連線Node;

詳細步驟

看到思路步驟概要後,相信我們的思路已經很清晰了。感覺是不是很simple,是的,實現也如此。到這裡了,我就開始編碼。但是為了教會大家,我提幾個疑問給大家:

樹的遍歷如何實現?(可以google,如果你學過數據結構當然simple了)
節點和節點這間使用什麼關聯?(next)
如何確定Node的位置?位置有什麼規律?(??)
如何實現兩個View之間的連線?(??)
……

其實問題還真的有一點。但是這些都不能妨礙我們的步伐,還是寫好已知的代碼吧 。

代碼

1.樹的節點。主要是一些需要的數據。父節點,值,子節點,是否對焦(對於將來用的),在樹形的層……

package com.owant.drawtreeview.model;

import java.util.LinkedList;

/**
 * Created by owant on 16/12/2016.
 */

public class TreeNode<T> {
 /**
  * the parent node,if root node parent node=null;
  */
 public TreeNode<T> parentNode;

 /**
  * the data value
  */
 public T value;

 /**
  * have the child nodes
  */
 public LinkedList<TreeNode<T>> childNodes;

 /**
  * focus tag for the tree add nodes
  */
 public boolean focus;

 /**
  * index of the tree floor
  */
 public int floor;

 public TreeNode(T value) {
  this.value = value;
  this.childNodes = new LinkedList<TreeNode<T>>();

//  this.focus = false;
//  this.parentNode = null;
 }

 public TreeNode<T> getParentNode() {
  return parentNode;
 }

 public void setParentNode(TreeNode<T> parentNode) {
  this.parentNode = parentNode;
 }

 public T getValue() {
  return value;
 }

 public void setValue(T value) {
  this.value = value;
 }

 public LinkedList<TreeNode<T>> getChildNodes() {
  return childNodes;
 }

 public void setChildNodes(LinkedList<TreeNode<T>> childNodes) {
  this.childNodes = childNodes;
 }

 public boolean isFocus() {
  return focus;
 }

 public void setFocus(boolean focus) {
  this.focus = focus;
 }

 public int getFloor() {
  return floor;
 }

 public void setFloor(int floor) {
  this.floor = floor;
 }
}



2.樹形。根節點,添加節點,遍歷,上一個節點,下一個節點,基於點拆分的上下節點集合。

package com.owant.drawtreeview.model;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;
import java.util.Stack;

/**
 * Created by owant on 16/12/2016.
 */

public class Tree<T> {

 /**
  * the root for the tree
  */
 public TreeNode<T> rootNode;

 public Tree(TreeNode<T> rootNode) {
  this.rootNode = rootNode;
 }

 /**
  * add the node in some father node
  *
  * @param start
  * @param nodes
  */
 public void addNode(TreeNode<T> start, TreeNode<T>... nodes) {
  int index = 1;
  TreeNode<T> temp = start;
  if (temp.getParentNode() != null) {
   index = temp.getParentNode().floor;
  }

  for (TreeNode<T> t : nodes) {
   t.setParentNode(start);
   t.setFloor(index);
   start.getChildNodes().add(t);
  }
 }

 public boolean remvoeNode(TreeNode<T> starNode, TreeNode<T> deleteNote) {
  boolean rm = false;
  int size = starNode.getChildNodes().size();
  if (size > 0) {
   rm = starNode.getChildNodes().remove(deleteNote);
  }
  return rm;
 }

 public TreeNode<T> getRootNode() {
  return rootNode;
 }

 public void setRootNode(TreeNode<T> rootNode) {
  this.rootNode = rootNode;
 }

 /**
  * 同一個父節點的上下
  *
  * @param midPreNode
  * @return
  * @throws NotFindNodeException
  */
 public TreeNode<T> getLowNode(TreeNode<T> midPreNode) {
  TreeNode<T> find = null;
  TreeNode<T> parentNode = midPreNode.getParentNode();

  if (parentNode != null && parentNode.getChildNodes().size() >= 2) {
   Deque<TreeNode<T>> queue = new ArrayDeque<>();
   TreeNode<T> rootNode = parentNode;
   queue.add(rootNode);
   boolean up = false;
   while (!queue.isEmpty()) {

    rootNode = (TreeNode<T>) queue.poll();
    if (up) {
     if (rootNode.getFloor() == midPreNode.getFloor()) {
      find = rootNode;
     }
     break;
    }

    //到了該元素
    if (rootNode == midPreNode) up = true;
    LinkedList<TreeNode<T>> childNodes = rootNode.getChildNodes();
    if (childNodes.size() > 0) {
     for (TreeNode<T> item : childNodes) {
      queue.add(item);
     }
    }
   }
  }
  return find;
 }

 public TreeNode<T> getPreNode(TreeNode<T> midPreNode) {

  TreeNode<T> parentNode = midPreNode.getParentNode();
  TreeNode<T> find = null;

  if (parentNode != null && parentNode.getChildNodes().size() > 0) {

   Deque<TreeNode<T>> queue = new ArrayDeque<>();
   TreeNode<T> rootNode = parentNode;
   queue.add(rootNode);

   while (!queue.isEmpty()) {
    rootNode = (TreeNode<T>) queue.poll();
    //到了該元素
    if (rootNode == midPreNode) {
     //返回之前的值
     break;
    }

    find = rootNode;
    LinkedList<TreeNode<T>> childNodes = rootNode.getChildNodes();
    if (childNodes.size() > 0) {
     for (TreeNode<T> item : childNodes) {
      queue.add(item);
     }
    }
   }

   if (find != null && find.getFloor() != midPreNode.getFloor()) {
    find = null;
   }
  }
  return find;
 }

 public ArrayList<TreeNode<T>> getAllLowNodes(TreeNode<T> addNode) {
  ArrayList<TreeNode<T>> array = new ArrayList<>();
  TreeNode<T> parentNode = addNode.getParentNode();
  while (parentNode != null) {
   TreeNode<T> lowNode = getLowNode(parentNode);
   while (lowNode != null) {
    array.add(lowNode);
    lowNode = getLowNode(lowNode);
   }
   parentNode = parentNode.getParentNode();
  }
  return array;
 }

 public ArrayList<TreeNode<T>> getAllPreNodes(TreeNode<T> addNode) {
  ArrayList<TreeNode<T>> array = new ArrayList<>();
  TreeNode<T> parentNode = addNode.getParentNode();
  while (parentNode != null) {
   TreeNode<T> lowNode = getPreNode(parentNode);
   while (lowNode != null) {
    array.add(lowNode);
    lowNode = getPreNode(lowNode);
   }
   parentNode = parentNode.getParentNode();
  }
  return array;
 }

 public LinkedList<TreeNode<T>> getNodeChildNodes(TreeNode<T> node) {
  return node.getChildNodes();
 }

 public void printTree() {
  Stack<TreeNode<T>> stack = new Stack<>();
  TreeNode<T> rootNode = getRootNode();
  stack.add(rootNode);
  while (!stack.isEmpty()) {
   TreeNode<T> pop = stack.pop();
   System.out.println(pop.getValue().toString());
   LinkedList<TreeNode<T>> childNodes = pop.getChildNodes();
   for (TreeNode<T> item : childNodes) {
    stack.add(item);
   }
  }
 }

 public void printTree2() {
  Deque<TreeNode<T>> queue = new ArrayDeque<>();
  TreeNode<T> rootNode = getRootNode();
  queue.add(rootNode);
  while (!queue.isEmpty()) {
   rootNode = (TreeNode<T>) queue.poll();
   System.out.println(rootNode.getValue().toString());

   LinkedList<TreeNode<T>> childNodes = rootNode.getChildNodes();
   if (childNodes.size() > 0) {
    for (TreeNode<T> item : childNodes) {
     queue.add(item);
    }
   }
  }

 }


}

3.測試模型 當我們實現了模型後,要寫一些列子來測試模型是否正確,進行打印,遍歷等測試,這是很重要的。對於樹形的node的上一個node和下一個node的理解等。 


4.樹形的View

package com.owant.drawtreeview.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;

import com.owant.drawtreeview.R;
import com.owant.drawtreeview.model.Tree;
import com.owant.drawtreeview.model.TreeNode;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;

/**
 * Created by owant on 09/01/2017.
 */

public class SuperTreeView extends ViewGroup {

  /**
   * the default x,y mDx
   */
  private int mDx;
  private int mDy;
  private int mWith;
  private int mHeight;
  private Context mContext;
  private Tree<String> mTree;
  private ArrayList<NodeView> mNodesViews;

  public SuperTreeView(Context context) {
    this(context, null, 0);
  }

  public SuperTreeView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
  }

  public SuperTreeView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    mContext = context;
    mNodesViews = new ArrayList<>();
    mContext = context;

    mDx = dp2px(mContext, 26);
    mDy = dp2px(mContext, 22);
  }

  /**
   * 添加view到Group
   */
  private void onAddNodeViews() {
    if (mTree != null) {
      TreeNode<String> rootNode = mTree.getRootNode();
      Deque<TreeNode<String>> deque = new ArrayDeque<>();
      deque.add(rootNode);
      while (!deque.isEmpty()) {
        TreeNode<String> poll = deque.poll();
        NodeView nodeView = new NodeView(mContext);
        nodeView.setTreeNode(poll);
        ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        nodeView.setLayoutParams(lp);

        this.addView(nodeView);
        mNodesViews.add(nodeView);

        LinkedList<TreeNode<String>> childNodes = poll.getChildNodes();
        for (TreeNode<String> ch : childNodes) {
          deque.push(ch);
        }
      }
    }
  }

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    final int size = getChildCount();
    for (int i = 0; i < size; i++) {
      measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec);
    }
  }

  @Override
  protected void onLayout(boolean changed, int l, int t, int r, int b) {
    mHeight = getMeasuredHeight();
    mWith = getMeasuredWidth();

    if (mTree != null) {
      NodeView rootView = findTreeNodeView(mTree.getRootNode());
      if (rootView != null) {
        //root的位置
        rootTreeViewLayout(rootView);
        //標准位置
        for (NodeView nv : mNodesViews) {
          standardTreeChildLayout(nv);
        }

        //基於父子的移動
        for (NodeView nv : mNodesViews) {
          fatherChildCorrect(nv);
        }

      }
    }

  }

  private void rootTreeViewLayout(NodeView rootView) {
    int lr = mDy;
    int tr = mHeight / 2 - rootView.getMeasuredHeight() / 2;
    int rr = lr + rootView.getMeasuredWidth();
    int br = tr + rootView.getMeasuredHeight();
    rootView.layout(lr, tr, rr, br);
  }

  @Override
  protected void dispatchDraw(Canvas canvas) {
    if (mTree != null) {
      drawTreeLine(canvas, mTree.getRootNode());
    }
    super.dispatchDraw(canvas);
  }

  /**
   * 標准的位置分布
   *
   * @param rootView
   */
  private void standardTreeChildLayout(NodeView rootView) {
    TreeNode<String> treeNode = rootView.getTreeNode();
    if (treeNode != null) {
      //所有的子節點
      LinkedList<TreeNode<String>> childNodes = treeNode.getChildNodes();
      int size = childNodes.size();
      int mid = size / 2;
      int r = size % 2;

      //基線
      //    b
      //  a-------
      //    c
      //
      int left = rootView.getRight() + mDx;
      int top = rootView.getTop() + rootView.getMeasuredHeight() / 2;

      int right = 0;
      int bottom = 0;

      if (size == 0) {
        return;
      } else if (size == 1) {
        NodeView midChildNodeView = findTreeNodeView(childNodes.get(0));

        top = top - midChildNodeView.getMeasuredHeight() / 2;
        right = left + midChildNodeView.getMeasuredWidth();
        bottom = top + midChildNodeView.getMeasuredHeight();
        midChildNodeView.layout(left, top, right, bottom);
      } else {

        int topLeft = left;
        int topTop = top;
        int topRight = 0;
        int topBottom = 0;

        int bottomLeft = left;
        int bottomTop = top;
        int bottomRight = 0;
        int bottomBottom = 0;

        if (r == 0) {//偶數
          for (int i = mid - 1; i >= 0; i--) {
            NodeView topView = findTreeNodeView(childNodes.get(i));
            NodeView bottomView = findTreeNodeView(childNodes.get(size - i - 1));


            if (i == mid - 1) {
              topTop = topTop - mDy / 2 - topView.getMeasuredHeight();
              topRight = topLeft + topView.getMeasuredWidth();
              topBottom = topTop + topView.getMeasuredHeight();

              bottomTop = bottomTop + mDy / 2;
              bottomRight = bottomLeft + bottomView.getMeasuredWidth();
              bottomBottom = bottomTop + bottomView.getMeasuredHeight();
            } else {
              topTop = topTop - mDy - topView.getMeasuredHeight();
              topRight = topLeft + topView.getMeasuredWidth();
              topBottom = topTop + topView.getMeasuredHeight();

              bottomTop = bottomTop + mDy;
              bottomRight = bottomLeft + bottomView.getMeasuredWidth();
              bottomBottom = bottomTop + bottomView.getMeasuredHeight();
            }

            topView.layout(topLeft, topTop, topRight, topBottom);
            bottomView.layout(bottomLeft, bottomTop, bottomRight, bottomBottom);

            bottomTop = bottomView.getBottom();
          }

        } else {
          NodeView midView = findTreeNodeView(childNodes.get(mid));
          midView.layout(left, top - midView.getMeasuredHeight() / 2, left + midView.getMeasuredWidth(),
              top - midView.getMeasuredHeight() / 2 + midView.getMeasuredHeight());

          topTop = midView.getTop();
          bottomTop = midView.getBottom();

          for (int i = mid - 1; i >= 0; i--) {
            NodeView topView = findTreeNodeView(childNodes.get(i));
            NodeView bottomView = findTreeNodeView(childNodes.get(size - i - 1));

            topTop = topTop - mDy - topView.getMeasuredHeight();
            topRight = topLeft + topView.getMeasuredWidth();
            topBottom = topTop + topView.getMeasuredHeight();

            bottomTop = bottomTop + mDy;
            bottomRight = bottomLeft + bottomView.getMeasuredWidth();
            bottomBottom = bottomTop + bottomView.getMeasuredHeight();

            topView.layout(topLeft, topTop, topRight, topBottom);
            bottomView.layout(bottomLeft, bottomTop, bottomRight, bottomBottom);
            bottomTop = bottomView.getBottom();
          }
        }
      }
    }

  }

  /**
   * 移動
   *
   * @param rootView
   * @param dy
   */
  private void moveNodeLayout(NodeView rootView, int dy) {

    Deque<TreeNode<String>> queue = new ArrayDeque<>();
    TreeNode<String> rootNode = rootView.getTreeNode();
    queue.add(rootNode);
    while (!queue.isEmpty()) {
      rootNode = (TreeNode<String>) queue.poll();
      rootView = findTreeNodeView(rootNode);
      int l = rootView.getLeft();
      int t = rootView.getTop() + dy;
      rootView.layout(l, t, l + rootView.getMeasuredWidth(), t + rootView.getMeasuredHeight());

      LinkedList<TreeNode<String>> childNodes = rootNode.getChildNodes();
      for (TreeNode<String> item : childNodes) {
        queue.add(item);
      }
    }
  }

  private void fatherChildCorrect(NodeView nv) {
    int count = nv.getTreeNode().getChildNodes().size();

    if (nv.getParent() != null && count >= 2) {
      TreeNode<String> tn = nv.getTreeNode().getChildNodes().get(0);
      TreeNode<String> bn = nv.getTreeNode().getChildNodes().get(count - 1);
      Log.i("see fc", nv.getTreeNode().getValue() + ":" + tn.getValue() + "," + bn.getValue());

      int topDr = nv.getTop() - findTreeNodeView(tn).getBottom() + mDy;
      int bnDr = findTreeNodeView(bn).getTop() - nv.getBottom() + mDy;
      //上移動
      ArrayList<TreeNode<String>> allLowNodes = mTree.getAllLowNodes(bn);
      ArrayList<TreeNode<String>> allPreNodes = mTree.getAllPreNodes(tn);

      for (TreeNode<String> low : allLowNodes) {
        NodeView view = findTreeNodeView(low);
        moveNodeLayout(view, bnDr);
      }

      for (TreeNode<String> pre : allPreNodes) {
        NodeView view = findTreeNodeView(pre);
        moveNodeLayout(view, -topDr);
      }
    }
  }


  /**
   * 繪制樹形的連線
   *
   * @param canvas
   * @param root
   */
  private void drawTreeLine(Canvas canvas, TreeNode<String> root) {
    NodeView fatherView = findTreeNodeView(root);
    if (fatherView != null) {
      LinkedList<TreeNode<String>> childNodes = root.getChildNodes();
      for (TreeNode<String> node : childNodes) {
        drawLineToView(canvas, fatherView, findTreeNodeView(node));
        drawTreeLine(canvas, node);
      }
    }
  }

  /**
   * 繪制兩個View直接的連線
   *
   * @param canvas
   * @param from
   * @param to
   */
  private void drawLineToView(Canvas canvas, View from, View to) {

    Paint paint = new Paint();
    paint.setAntiAlias(true);
    paint.setStyle(Paint.Style.STROKE);

    float width = 2f;

    paint.setStrokeWidth(dp2px(mContext, width));
    paint.setColor(mContext.getResources().getColor(R.color.chelsea_cucumber));

    int top = from.getTop();
    int formY = top + from.getMeasuredHeight() / 2;
    int formX = from.getRight();

    int top1 = to.getTop();
    int toY = top1 + to.getMeasuredHeight() / 2;
    int toX = to.getLeft();

    Path path = new Path();
    path.moveTo(formX, formY);
    path.quadTo(toX - dp2px(mContext, 15), toY, toX, toY);

    canvas.drawPath(path, paint);
  }

  private NodeView findTreeNodeView(TreeNode<String> node) {
    NodeView v = null;
    for (NodeView view : mNodesViews) {
      if (view.getTreeNode() == node) {
        v = view;
        continue;
      }
    }
    return v;
  }

  public int dp2px(Context context, float dpVal) {
    int result = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, context.getResources()
        .getDisplayMetrics());
    return result;
  }

  public void setTree(Tree<String> tree) {
    this.mTree = tree;
    onAddNodeViews();
  }

  public Tree<String> getTree() {
    return mTree;
  }
}

粘貼代碼後發現,沒有什麼好說了,對於讀者來說,應該是一臉懵逼的。畢竟,那個位置是如何確定的呀,view和view的連線呀…… 對於整個View來說這是最難的,我也是探索了好久才得出結論的。首先,對於一個只有兩層的樹形來說,如圖:

PQRS是基於F來計算的,之後分布。之後我就得到的方法如下:

/**
   * 標准的位置分布
   *
   * @param rootView
   */
  private void standardTreeChildLayout(NodeView rootView) {
    TreeNode<String> treeNode = rootView.getTreeNode();
    if (treeNode != null) {
      //所有的子節點
      LinkedList<TreeNode<String>> childNodes = treeNode.getChildNodes();
      int size = childNodes.size();
      int mid = size / 2;
      int r = size % 2;

      //基線
      //    b
      //  a-------
      //    c
      //
      int left = rootView.getRight() + mDx;
      int top = rootView.getTop() + rootView.getMeasuredHeight() / 2;

      int right = 0;
      int bottom = 0;

      if (size == 0) {
        return;
      } else if (size == 1) {
        NodeView midChildNodeView = findTreeNodeView(childNodes.get(0));

        top = top - midChildNodeView.getMeasuredHeight() / 2;
        right = left + midChildNodeView.getMeasuredWidth();
        bottom = top + midChildNodeView.getMeasuredHeight();
        midChildNodeView.layout(left, top, right, bottom);
      } else {

        int topLeft = left;
        int topTop = top;
        int topRight = 0;
        int topBottom = 0;

        int bottomLeft = left;
        int bottomTop = top;
        int bottomRight = 0;
        int bottomBottom = 0;

        if (r == 0) {//偶數
          for (int i = mid - 1; i >= 0; i--) {
            NodeView topView = findTreeNodeView(childNodes.get(i));
            NodeView bottomView = findTreeNodeView(childNodes.get(size - i - 1));


            if (i == mid - 1) {
              topTop = topTop - mDy / 2 - topView.getMeasuredHeight();
              topRight = topLeft + topView.getMeasuredWidth();
              topBottom = topTop + topView.getMeasuredHeight();

              bottomTop = bottomTop + mDy / 2;
              bottomRight = bottomLeft + bottomView.getMeasuredWidth();
              bottomBottom = bottomTop + bottomView.getMeasuredHeight();
            } else {
              topTop = topTop - mDy - topView.getMeasuredHeight();
              topRight = topLeft + topView.getMeasuredWidth();
              topBottom = topTop + topView.getMeasuredHeight();

              bottomTop = bottomTop + mDy;
              bottomRight = bottomLeft + bottomView.getMeasuredWidth();
              bottomBottom = bottomTop + bottomView.getMeasuredHeight();
            }

            topView.layout(topLeft, topTop, topRight, topBottom);
            bottomView.layout(bottomLeft, bottomTop, bottomRight, bottomBottom);

            bottomTop = bottomView.getBottom();
          }

        } else {
          NodeView midView = findTreeNodeView(childNodes.get(mid));
          midView.layout(left, top - midView.getMeasuredHeight() / 2, left + midView.getMeasuredWidth(),
              top - midView.getMeasuredHeight() / 2 + midView.getMeasuredHeight());

          topTop = midView.getTop();
          bottomTop = midView.getBottom();

          for (int i = mid - 1; i >= 0; i--) {
            NodeView topView = findTreeNodeView(childNodes.get(i));
            NodeView bottomView = findTreeNodeView(childNodes.get(size - i - 1));

            topTop = topTop - mDy - topView.getMeasuredHeight();
            topRight = topLeft + topView.getMeasuredWidth();
            topBottom = topTop + topView.getMeasuredHeight();

            bottomTop = bottomTop + mDy;
            bottomRight = bottomLeft + bottomView.getMeasuredWidth();
            bottomBottom = bottomTop + bottomView.getMeasuredHeight();

            topView.layout(topLeft, topTop, topRight, topBottom);
            bottomView.layout(bottomLeft, bottomTop, bottomRight, bottomBottom);
            bottomTop = bottomView.getBottom();
          }
        }
      }
    }

  }

之後等到的View情況如下:

說明我們還需要糾正。下面是糾正的探索,我精簡一下結構如下情況:


發現:

B需要在E的上面;
D需要在I的下面;

就是EI要撐開ID的位置。之後我們可以先寫這個算法,發現基本可以了。但是還是有問題,同層的還是會重合,只有我們又進行同層的糾正。發現好像解決了,其實還是不行,測試還是發現問題,對於單伸長還有問題,之後又是修改…………

最後發現……這裡就不說了,就是自己要探索啦。

總結

最後我才發現了那個完善的糾正算法,就是代碼了的。大家可以在我的github中找到我之前的TreeView中的那個位置算法探索。歡迎大家支持:https://github.com/owant/TreeView

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持本站。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved