標籤:

Android樹狀圖(checkbox)

點擊上方「

程序員大咖

」,選擇「置頂公眾號」

關鍵時刻,第一時間送達!

作者:她的夢z鏈接:https://www.jianshu.com/p/349c92772ba1

程序員大咖整理髮布,轉載請聯繫作者獲得授權

實在不知道說什麼好了,這個東西以前也沒做過,這兩天公司有這方面的需求,就實現一下,然後把功能跟大家分享一下,以後有需要直接拿去用就好。先上個圖表達一下我此時的心情,畢竟已經完成要求了···

效果展示:

分析一波:

  • 1.層級父節點與子節點的關聯

  • 2.布局的復用

  • 3.層級展開與關閉,顯示與隱藏問題

  • 4.checkbox的標記勾選

功能的初步準備

具體的代碼mean,項目注釋都有··

一、數據的實體類

public

 

class

 

Node

<

T

B

{    

/**     * 數據源的欄位     */

    

private

 String title;    

private

 String bmid;    

private

 String content;    

private

 String code;    

private

 String childBmid;    

/**     * ****************** 分級樹狀等欄位     */

    

//傳入的實體對象

    

public

 B bean;    

//父級id子級pid

    

private

 T id;    

//根節點pId為0

    

private

 T pId;    

//節點名稱

    

private

 String name;    

//當前的級別

    

private

 

int

 level;    

//是否展開

    

private

 

boolean

 isExpand = 

false

;    

//子節點數據 ,套用當前node

    

private

 List children = 

new

 ArrayList<>();    

//父節點

    

private

 Node parent;    

//是否被checked選中

    

private

 

boolean

 isChecked;    

public

 

Node

()

 

{    }    

public

 

Node

(T id, T pId, String name)

 

{        

super

();        

this

.id = id;        

this

.pId = pId;        

this

.name = name;    }    

public

 

Node

(T id, T pId, String name, B bean)

 

{        

super

();        

this

.id = id;        

this

.pId = pId;        

this

.name = name;        

this

.bean = bean;    }    

public

 

boolean

 

isChecked

()

 

{        

return

 isChecked;    }    

public

 

void

 

setChecked

(

boolean

 isChecked)

 

{        

this

.isChecked = isChecked;    }    

public

 String 

getTitle

()

 

{        

return

 title;    }    

public

 

void

 

setTitle

(String title)

 

{        

this

.title = title;    }    

public

 String 

getBmid

()

 

{        

return

 bmid;    }    

public

 

void

 

setBmid

(String bmid)

 

{        

this

.bmid = bmid;    }    

public

 String 

getContent

()

 

{        

return

 content;    }    

public

 

void

 

setContent

(String content)

 

{        

this

.content = content;    }    

public

 String 

getCode

()

 

{        

return

 code;    }    

public

 

void

 

setCode

(String code)

 

{        

this

.code = code;    }    

public

 String 

getChildBmid

()

 

{        

return

 childBmid;    }    

public

 

void

 

setChildBmid

(String childBmid)

 

{        

this

.childBmid = childBmid;    }    

public

 T 

getId

()

 

{        

return

 id;    }    

public

 

void

 

setId

(T id)

 

{        

this

.id = id;    }    

public

 T 

getpId

()

 

{        

return

 pId;    }    

public

 

void

 

setpId

(T pId)

 

{        

this

.pId = pId;    }    

public

 String 

getName

()

 

{        

return

 name;    }    

public

 

void

 

setName

(String name)

 

{        

this

.name = name;    }    

public

 

void

 

setLevel

(

int

 level)

 

{        

this

.level = level;    }    

public

 

boolean

 

isExpand

()

 

{        

return

 isExpand;    }    

public

 List 

getChildren

()

 

{        

return

 children;    }    

public

 

void

 

setChildren

(List children)

 

{        

this

.children = children;    }    

public

 Node 

getParent

()

 

{        

return

 parent;    }    

public

 

void

 

setParent

(Node parent)

 

{        

this

.parent = parent;    }    

/**     * 是否為跟節點     */

    

public

 

boolean

 

isRoot

()

 

{        

return

 parent == 

null

;    }    

/**     * 判斷父節點是否展開     */

    

public

 

boolean

 

isParentExpand

()

 

{        

if

 (parent == 

null

)            

return

 

false

;        

return

 parent.isExpand();    }    

/**     * 是否是葉子界點     */

    

public

 

boolean

 

isLeaf

()

 

{        

return

 children.size() == 

0

;    }    

/**     * 獲取當前所在層級,     * 設置層級間隔     */

    

public

 

int

 

getLevel

()

 

{        

return

 parent == 

null

 ? 

0

 : parent.getLevel() + 

1

;    }    

/**     * 設置展開     */

    

public

 

void

 

setExpand

(

boolean

 isExpand)

 

{        

this

.isExpand = isExpand;        

if

 (!isExpand) {            

for

 (Node node : children) {                node.setExpand(isExpand);            }        }    }}

二、設置節點關係

public

 

class

 

TreeHelper

 

{    

/**     * 傳入node  返回排序後的Node     */

    

public

 

static

 List 

getSortedNodes

(List datas,                                            

int

 defaultExpandLevel)

 

{        List result = 

new

 ArrayList();        

// 設置Node間父子關係

        List nodes = convetData2Node(datas);        

// 拿到根節點

        List rootNodes = getRootNodes(nodes);        

// 排序以及設置Node間關係

        

for

 (Node node : rootNodes) {            addNode(result, node, defaultExpandLevel, 

1

);        }        

return

 result;    }    

/**     * 過濾出所有可見的Node     */

    

public

 

static

 List 

filterVisibleNode

(List nodes)

 

{        List result = 

new

 ArrayList();        

for

 (Node node : nodes) {            

// 如果為跟節點,或者上層目錄為展開狀態

            

if

 (node.isRoot() || node.isParentExpand()) {                result.add(node);            }        }        

return

 result;    }    

/**     * 設置Node間,父子關係;讓每兩個節點都比較一次,即可設置其中的關係     */

    

private

 

static

 List 

convetData2Node

(List nodes)

 

{        

for

 (

int

 i = 

0

; i < nodes.size(); i++) {            Node n = nodes.get(i);            

for

 (

int

 j = i + 

1

; j < nodes.size(); j++) {                Node m = nodes.get(j);                

if

 (m.getpId() 

instanceof

 String) {                    

if

 (m.getpId().equals(n.getId())) {                        n.getChildren().add(m);                        m.setParent(n);                    } 

else

 

if

 (m.getId().equals(n.getpId())) {                        m.getChildren().add(n);                        n.setParent(m);                    }                } 

else

 {                    

if

 (m.getpId() == n.getId()) {                        n.getChildren().add(m);                        m.setParent(n);                    } 

else

 

if

 (m.getId() == n.getpId()) {                        m.getChildren().add(n);                        n.setParent(m);                    }                }            }        }        

return

 nodes;    }    

// 拿到根節點

    

private

 

static

 List 

getRootNodes

(List nodes)

 

{        List root = 

new

 ArrayList();        

for

 (Node node : nodes) {            

if

 (node.isRoot())                root.add(node);        }        

return

 root;    }    

/**     * 把一個節點上的所有的內容都掛上去     */

    

private

 

static

  

void

 

addNode

(List nodes, Node node,                                       

int

 defaultExpandLeval, 

int

 currentLevel)

 

{        nodes.add(node);        

if

 (defaultExpandLeval >= currentLevel) {            node.setExpand(

true

);        }        

if

 (node.isLeaf())            

return

;        

for

 (

int

 i = 

0

; i < node.getChildren().size(); i++) {            addNode(nodes, node.getChildren().get(i), defaultExpandLeval,                    currentLevel + 

1

);        }    }}

三、Adapter的封裝

public

 

abstract

 

class

 

TreeListViewAdapter

 

extends

 

BaseAdapter

 

{    

protected

 Context mContext;    

/**     * 存儲所有可見的Node     */

    

protected

 List mNodes = 

new

 ArrayList<>();    

protected

 LayoutInflater mInflater;    

/**     * 存儲所有的Node     */

    

protected

 List mAllNodes = 

new

 ArrayList<>();    

public

 

TreeListViewAdapter

(ListView mTree, Context context, List datas,                               

int

 defaultExpandLevel)

 

{        mContext = context;        

/**         * 對所有的Node進行排序         */

        mAllNodes = TreeHelper.getSortedNodes(datas, defaultExpandLevel);        

/**         * 過濾出可見的Node         */

        mNodes = TreeHelper.filterVisibleNode(mAllNodes);        mInflater = LayoutInflater.from(context);        

/**         * 設置節點點擊時,可以展開以及關閉;並且將ItemClick事件繼續往外公布         */

        mTree.setOnItemClickListener(

new

 AdapterView.OnItemClickListener() {            

@Override

            

public

 

void

 

onItemClick

(AdapterView parent, View view,                                    

int

 position, 

long

 id)

 

{                expandOrCollapse(position);            }        });    }    

/**     * 相應ListView的點擊事件 展開或關閉某節點     */

    

public

 

void

 

expandOrCollapse

(

int

 position)

 

{        Node n = mNodes.get(position);        

if

 (n != 

null

) {

// 排除傳入參數錯誤異常

            

if

 (!n.isLeaf()) {                n.setExpand(!n.isExpand());                mNodes = TreeHelper.filterVisibleNode(mAllNodes);                notifyDataSetChanged();

// 刷新視圖

            }        }    }    

@Override

    

public

 

int

 

getCount

()

 

{        

return

 mNodes.size();    }    

@Override

    

public

 Object 

getItem

(

int

 position)

 

{        

return

 mNodes.get(position);    }    

@Override

    

public

 

long

 

getItemId

(

int

 position)

 

{        

return

 position;    }    

@Override

    

public

 View 

getView

(

int

 position, View convertView, ViewGroup parent)

 

{        Node node = mNodes.get(position);        convertView = getConvertView(node, position, convertView, parent);        

// 設置內邊距

        convertView.setPadding(node.getLevel() * 

50

3

3

3

);        

return

 convertView;    }    

/**     * 設置多選     */

    

protected

 

void

 

setChecked

(

final

 Node node, 

boolean

 checked)

 

{        node.setChecked(checked);        setChildChecked(node, checked);        

if

 (node.getParent() != 

null

)            setNodeParentChecked(node.getParent(), checked);        notifyDataSetChanged();    }    

/**     * 設置是否選中     */

    

public

  

void

 

setChildChecked

(Node node, 

boolean

 checked)

 

{        

if

 (!node.isLeaf()) {            node.setChecked(checked);            

for

 (Node childrenNode : node.getChildren()) {                setChildChecked(childrenNode, checked);            }        } 

else

 {            node.setChecked(checked);        }    }    

private

 

void

 

setNodeParentChecked

(Node node, 

boolean

 checked)

 

{        

if

 (checked) {            node.setChecked(checked);            

if

 (node.getParent() != 

null

)                setNodeParentChecked(node.getParent(), checked);        } 

else

 {            List childrens = node.getChildren();            

boolean

 isChecked = 

false

;            

for

 (Node children : childrens) {                

if

 (children.isChecked()) {                    isChecked = 

true

;                }            }            

//如果所有自節點都沒有被選中 父節點也不選中

            

if

 (!isChecked) {                node.setChecked(checked);            }            

if

 (node.getParent() != 

null

)                setNodeParentChecked(node.getParent(), checked);        }    }    

public

 

abstract

 View 

getConvertView

(Node node, 

int

 position,                                        View convertView, ViewGroup parent)

;}

Adapter實現類

一、布局代碼