-
}
-
public void setParent(Node parent)
-
{
-
this.parent = parent;
-
}
-
/**
-
* 是否为跟节点
-
*
-
* @return
-
*/
-
public boolean isRoot()
-
{
-
return parent == null;
-
}
-
/**
-
* 判断父节点是否展开
-
*
-
* @return
-
*/
-
public boolean isParentExpand()
-
{
-
if (parent == null)
-
return false;
-
return parent.isExpand();
-
}
-
/**
-
* 是否是叶子界点
-
*
-
* @return
-
*/
-
public boolean isLeaf()
-
{
-
return children.size() == 0;
-
}
-
/**
-
* 获取level
-
*/
-
public int getLevel()
-
{
-
return parent == null ? 0 : parent.getLevel() + 1;
-
}
-
/**
-
* 设置展开
-
*
-
* @param isExpand
-
*/
-
public void setExpand(boolean isExpand)
-
{
-
this.isExpand = isExpand;
-
if (!isExpand)
-
{
-
for (Node node : children)
-
{
-
node.setExpand(isExpand);
-
}
-
}
-
}
-
}
包含了树节点一些常见的属性,一些常见的方法;对于getLevel,setExpand这些方法,大家可以好好看看~
有了Node,刚才的用法中,出现的就是我们Adapter所继承的超类:TreeListViewAdapter;核心代码都在里面,我们准备去一探究竟:
代码不是很长,直接完整的贴出:
[java] view plain copy
-
package com.zhy.tree.bean;
-
import java.util.List;
-
import android.content.Context;
-
import android.view.LayoutInflater;
-
import android.view.View;
-
import android.view.ViewGroup;
-
import android.widget.AdapterView;
-
import android.widget.AdapterView.OnItemClickListener;
-
import android.widget.BaseAdapter;
-
import android.widget.ListView;
-
public abstract class TreeListViewAdapter extends BaseAdapter
-
{
-
protected Context mContext;
-
/**
-
* 存储所有可见的Node
-
*/
-
protected List mNodes;
-
protected LayoutInflater mInflater;
-
/**
-
* 存储所有的Node
-
*/
-
protected List mAllNodes;
-
/**
-
* 点击的回调接口
-
*/
-
private OnTreeNodeClickListener onTreeNodeClickListener;
-
public interface OnTreeNodeClickListener
-
{
-
void onClick(Node node, int position);
-
}
-
public void setOnTreeNodeClickListener(
-
OnTreeNodeClickListener onTreeNodeClickListener)
-
{
-
this.onTreeNodeClickListener = onTreeNodeClickListener;
-
}
-
/**
-
*
-
* @param mTree
-
* @param context
-
* @param datas
-
* @param defaultExpandLevel
-
* 默认展开几级树
-
* @throws IllegalArgumentException
-
* @throws IllegalAccessException
-
*/
-
public TreeListViewAdapter(ListView mTree, Context context, List datas,
-
int defaultExpandLevel) throws IllegalArgumentException,
-
IllegalAccessException
-
{
-
mContext = context;
-
/**
-
* 对所有的Node进行排序
-
*/
-
mAllNodes = TreeHelper.getSortedNodes(datas, defaultExpandLevel);
-
/**
-
* 过滤出可见的Node
-
*/
-
mNodes = TreeHelper.filterVisibleNode(mAllNodes);
-
mInflater = LayoutInflater.from(context);
-
/**
-
* 设置节点点击时,可以展开以及关闭;并且将ItemClick事件继续往外公布
-
*/
-
mTree.setOnItemClickListener(new OnItemClickListener()
-
{
-
@Override
-
public void onItemClick(AdapterView<?> parent, View view,
-
int position, long id)
-
{
-
expandOrCollapse(position);
-
if (onTreeNodeClickListener != null)
-
{
-
onTreeNodeClickListener.onClick(mNodes.get(position),
-
position);
-
}
-
}
-
});
-
}
-
/**
-
* 相应ListView的点击事件 展开或关闭某节点
-
*
-
* @param position
-
*/
-
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() * 30, 3, 3, 3);
-
return convertView;
-
}
-
public abstract View getConvertView(Node node, int position,
-
View convertView, ViewGroup parent);
-
}
首先我们的类继承自BaseAdapter,然后我们对应的数据集是,过滤出的可见的Node;
我们的构造方法默认接收4个参数:listview,context,mdatas,以及默认展开的级数:0只显示根节点;
可以在构造方法中看到:对用户传入的数据集做了排序,和过滤的操作;一会再看这些方法,这些方法我们使用了一个TreeHelper进行了封装。
注:如果你觉得你的Item布局十分复杂,且布局会展示Bean的其他数据,那么为了方便,你可以让Node中包含一个泛型T , 每个Node携带与之对于的Bean的所有数据;
可以看到我们还直接为Item设置了点击事件,因为我们树,默认就有点击父节点展开与关闭;但是为了让用户依然可用点击监听,我们自定义了一个点击的回调供用户使用;
当用户点击时,默认调用expandOrCollapse方法,将当然节点重置展开标志,然后重新过滤出可见的Node,最后notifyDataSetChanged即可;
其他的方法都是BaseAdapter默认的一些方法了。
下面我们看下TreeHelper中的一些方法:
首先看TreeListViewAdapter构造方法中用到的两个方法:
[java] view plain copy
-
/**
-
* 传入我们的普通bean,转化为我们排序后的Node
-
* @param datas
-
* @param defaultExpandLevel
-
* @return
-
* @throws IllegalArgumentException
-
* @throws IllegalAccessException
-
*/
-
public static List getSortedNodes(List datas,
-
int defaultExpandLevel) throws IllegalArgumentException,
-
IllegalAccessException
-
{
-
List result = new ArrayList();
-
//将用户数据转化为List以及设置Node间关系
-
List nodes = convetData2Node(datas);
-
//拿到根节点
-
List rootNodes = getRootNodes(nodes);
-
//排序
-
for (Node node : rootNodes)
-
{
-
addNode(result, node, defaultExpandLevel, 1);
-
}
-
return result;
-
}
拿到用户传入的数据,转化为List以及设置Node间关系,然后根节点,从根往下遍历进行排序;
接下来看:filterVisibleNode
[java] view plain copy
-
/**
-
* 过滤出所有可见的Node
-
*
-
* @param nodes
-
* @return
-
*/
-
public static List filterVisibleNode(List nodes)
-
{
-
List result = new ArrayList();
-
for (Node node : nodes)
-
{
-
// 如果为跟节点,或者上层目录为展开状态
-
if (node.isRoot() || node.isParentExpand())
-
{
-
setNodeIcon(node);
-
result.add(node);
-
}
-
}
-
return result;
-
}
过滤Node的代码很简单,遍历所有的Node,只要是根节点或者父节点是展开状态就添加返回;
最后看看这两个方法用到的别的一些私有方法:
[java] view plain copy
-
/**
-
* 将我们的数据转化为树的节点
-
*
-
* @param datas
-
* @return
-
* @throws NoSuchFieldException
-
* @throws IllegalAccessException
-
* @throws IllegalArgumentException
-
*/
-
private static List convetData2Node(List datas)
-
throws IllegalArgumentException, IllegalAccessException
-
{
-
List nodes = new ArrayList();
-
Node node = null;
-
for (T t : datas)
-
{
-
int id = -1;
-
int pId = -1;
-
String label = null;
-
Class<? extends Object> clazz = t.getClass();
-
Field[] declaredFields = clazz.getDeclaredFields();
-
for (Field f : declaredFields)
-
{
-
if (f.getAnnotation(TreeNodeId.class) != null)
-
{
-
f.setAccessible(true);
-
id = f.getInt(t);
-
}
-
if (f.getAnnotation(TreeNodePid.class) != null)
-
{
-
f.setAccessible(true);
-
pId = f.getInt(t);
-
}
-
if (f.getAnnotation(TreeNodeLabel.class) != null)
-
{
-
f.setAccessible(true);
-
label = (String) f.get(t);
-
}
-
if (id != -1 && pId != -1 && label != null)
-
{
-
break;
-
}
-
}
-
node = new Node(id, pId, label);
-
nodes.add(node);
-
}
-
/**
-
* 设置Node间,父子关系;让每两个节点都比较一次,即可设置其中的关系
-
*/
-
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() == n.getId())
-
{
-
n.getChildren().add(m);
-
m.setParent(n);
-
} else if (m.getId() == n.getpId())
-
{
-
m.getChildren().add(n);
-
n.setParent(m);
-
}
-
}
-
}
-
// 设置图片
-
for (Node n : nodes)
-
{
-
setNodeIcon(n);
-
}
-
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);
-
}
-
}
-
/**
-
* 设置节点的图标
-
*
-
* @param node
-
*/
-
private static void setNodeIcon(Node node)
-
{
-
if (node.getChildren().size() > 0 && node.isExpand())
-
{
-
node.setIcon(R.drawable.tree_ex);
-
} else if (node.getChildren().size() > 0 && !node.isExpand())
-
{
-
node.setIcon(R.drawable.tree_ec);
-
} else
-
node.setIcon(-1);
-
}
convetData2Node即遍历用户传入的Bean,转化为Node,其中Id,pId,label通过注解加反射获取;然后设置Node间关系;
getRootNodes 这个简单,获得根节点
addNode :通过递归的方式,把一个节点上的所有的子节点等都按顺序放入;
setNodeIcon :设置图标,这里标明,我们的jar还依赖两个小图标,即两个三角形;如果你觉得树不需要这样的图标,可以去掉;
最后就是我们的3个注解类了,没撒用,就启到一个标识的作用
TreeNodeId
[java] view plain copy
-
package com.zhy.tree.bean;
-
import java.lang.annotation.ElementType;
-
import java.lang.annotation.Retention;
-
import java.lang.annotation.RetentionPolicy;
-
import java.lang.annotation.Target;
-
@Target(ElementType.FIELD)
-
@Retention(RetentionPolicy.RUNTIME)
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
最后
其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。
上面分享的百度、腾讯、网易、字节跳动、阿里等公司2021年的高频面试题,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,上面只是以图片的形式给大家展示一部分。
【Android思维脑图(技能树)】
知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。
【Android高级架构视频学习资源】
大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**
深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-yeuQ7bAf-1711298081031)]
[外链图片转存中…(img-RtjBRCsY-1711298081032)]
[外链图片转存中…(img-FFJIyzyX-1711298081032)]
[外链图片转存中…(img-uCsjeT8Y-1711298081032)]
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-9TvWDJqD-1711298081032)]
最后
其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。
上面分享的百度、腾讯、网易、字节跳动、阿里等公司2021年的高频面试题,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,上面只是以图片的形式给大家展示一部分。
【Android思维脑图(技能树)】
知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。
[外链图片转存中…(img-d47pJbIZ-1711298081033)]
【Android高级架构视频学习资源】
**Android部分精讲视频领取学习后更加是如虎添翼!**进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!