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
Listnew
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
StringgetTitle
()
{return
title; }public
void
setTitle
(String title)
{this
.title = title; }public
StringgetBmid
()
{return
bmid; }public
void
setBmid
(String bmid)
{this
.bmid = bmid; }public
StringgetContent
()
{return
content; }public
void
setContent
(String content)
{this
.content = content; }public
StringgetCode
()
{return
code; }public
void
setCode
(String code)
{this
.code = code; }public
StringgetChildBmid
()
{return
childBmid; }public
void
setChildBmid
(String childBmid)
{this
.childBmid = childBmid; }public
TgetId
()
{return
id; }public
void
setId
(T id)
{this
.id = id; }public
TgetpId
()
{return
pId; }public
void
setpId
(T pId)
{this
.pId = pId; }public
StringgetName
()
{return
name; }public
void
setName
(String name)
{this
.name = name; }public
void
setLevel
(
int
level) {this
.level = level; }public
boolean
isExpand
()
{return
isExpand; }public
ListgetChildren
()
return
children; }public
void
setChildren
(List
this
.children = children; }public
NodegetParent
()
{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
ListgetSortedNodes
(List int
new
ArrayList// 設置Node間父子關係
List// 拿到根節點
List// 排序以及設置Node間關係
for
(Node node : rootNodes) { addNode(result, node, defaultExpandLevel,1
); }return
result; }/** * 過濾出所有可見的Node */
public
static
ListfilterVisibleNode
(List
new
ArrayListfor
(Node node : nodes) {// 如果為跟節點,或者上層目錄為展開狀態
if
(node.isRoot() || node.isParentExpand()) { result.add(node); } }return
result; }/** * 設置Node間,父子關係;讓每兩個節點都比較一次,即可設置其中的關係 */
private
static
ListconvetData2Node
(List
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
ListgetRootNodes
(List
new
ArrayListfor
(Node node : nodes) {if
(node.isRoot()) root.add(node); }return
root; }/** * 把一個節點上的所有的內容都掛上去 */
private
static
void
addNode
(List int int
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
Listnew
ArrayList<>();protected
LayoutInflater mInflater;/** * 存儲所有的Node */
protected
Listnew
ArrayList<>();public
TreeListViewAdapter
(ListView mTree, Context context, List int
/** * 對所有的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
ObjectgetItem
(
int
position) {return
mNodes.get(position); }@Override
public
long
getItemId
(
int
position) {return
position; }@Override
public
ViewgetView
(
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 boolean
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
{ Listboolean
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
ViewgetConvertView
(Node node,
int
position, View convertView, ViewGroup parent);}Adapter實現類
一、布局代碼