树形列表
缩进目录
假设json数据的bean类如下:
DataBean.java
public class DataBean {
private List<MainChapterBean> mainChapterList;
public List<MainChapterBean> getMainChapterList() {
return mainChapterList;
}
public void setMainChapterList(List<MainChapterBean> mainChapterList) {
this.mainChapterList = mainChapterList;
}
public static class MainChapterBean {
private int chapterId;
private String chapterTitle;
private List<SubChapterBean> subChapterList;
public int getChapterId() {
return chapterId;
}
public void setChapterId(int chapterId) {
this.chapterId = chapterId;
}
public String getChapterTitle() {
return chapterTitle;
}
public void setChapterTitle(String chapterTitle) {
this.chapterTitle = chapterTitle;
}
public List<SubChapterBean> getSubChapterList() {
return subChapterList;
}
public void setSubChapterList(List<SubChapterBean> subChapterList) {
this.subChapterList = subChapterList;
}
public static class SubChapterBean {
private int chapterId;
private String chapterTitle;
private List<SubChapterBean> subChapterList;
public int getChapterId() {
return chapterId;
}
public void setChapterId(int chapterId) {
this.chapterId = chapterId;
}
public String getChapterTitle() {
return chapterTitle;
}
public void setChapterTitle(String chapterTitle) {
this.chapterTitle = chapterTitle;
}
public List<SubChapterBean> getSubChapterList() {
return subChapterList;
}
public void setSubChapterList(List<SubChapterBean> subChapterList) {
this.subChapterList = subChapterList;
}
@NonNull
@Override
public String toString() {
return new Gson().toJson(this);
}
}
@NonNull
@Override
public String toString() {
return new Gson().toJson(this);
}
}
@NonNull
@Override
public String toString() {
return new Gson().toJson(this);
}
}
这个bean类数据类似于
node =
{title:“1”, id:1, children:[
{title:“1.1”, id:2, children:[ {title:“1.1.1”, id:3 children:[ ] }, {title:“1.1.2”, id:4, children:[ ] } ] },
{title:“2”, id:5, children:[ {title:“2.1”, id:6, children:[ ] }, {title:“2.2”, id:7, children:[ ] } ] }
] }
1. 打印列表
总之就是一个list包含一个childrenList,childrenList里面可能又包含另一个childrenList。
要把这些数据全部读出来并且排成一个目录列表,显然是使用深度优先搜索:遍历完一个章节的所有子目录之后,把数据塞到另一个list里面,然后再去遍历另一个章节。
AdapterBean.java
public class AdapterBean {
private int chapterId;
private String chapterTitle;
private int level;
public int getChapterId() {
return chapterId;
}
public void setChapterId(int chapterId) {
this.chapterId = chapterId;
}
public String getChapterTitle() {
return chapterTitle;
}
public void setChapterTitle(String chapterTitle) {
this.chapterTitle = chapterTitle;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
}
MainActivity.java
private void handleList(List<DataBean> dataList) {
if (dataList == null || dataList.getMainChapterList() == null) return;
List<AdapterBean> adapterList = createAdapterList(dataList.getMainChapterList());
adapter.setData(adapterList);
}
private void createAdapterList(List<MainChapterBean> mainChapterList) {
List<AdapterBean> adapterList = new ArrayList<>();
for (int i = 0; i < mainChapterList.size(); i++) {
MainChapterBean item = mainChapterList.get(i);
AdapterBean bean = new AdapterBean();
bean.setChapterId(item.getChapterId);
bean.setChapterTitle(item.getChapterTitle);
bean.setLevel(0);
adapterList.add(bean);
if (item.getSubChapterList() != null && !item.getSubChapterList().isEmpty()) {
dfs(1, item.getSubChapterList(), adapterList);
}
}
}
private void dfs(int level, List<SubChapterBean> subChapterList, List<AdapterBean> adapterList) {
if (subChapterList == null) return;
for (int i = 0; i < subChapterList.size(); i++) {
SubChapterBean item = subChapterList.get(i);
AdapterBean bean = new AdapterBean();
bean.setChapterTitle(item.getChapterTitle());
bean.setChapterId(item.getChapterId());
bean.setLevel(level);
adapterList.add(bean);
if (item.getSubChapterList() != null && !item.getSubChapterList().isEmpty()) {
dfs(level + 1, item.getSubChapterList(), adapterList);
}
}
}
如果要对位于不同层的目录应用不同样式的话,那么在遍历的过程中就要额外加入一个level变量来记录当前遍历到第几层,在onBindViewHolder()
里面根据每个item的level来设置样式。
如果是设置缩进的话,尽量使用padding
而不是margin
,防止之后要进行item的显示和隐藏操作的时候,因为ViewHolder的itemView的margin而造成就算item隐藏了也出现空白的间隔。
2. 树形列表
如果要实现点击父目录的时候子目录可以显示或隐藏的话,需要在AdapterBean里面额外添加参数来记录。
实现点击显示,显示的是点击的那个目录的一层子目录,用循环。
实现点击隐藏,隐藏的是点击的那个目录的所有子目录,用递归。
AdapterBean
public class AdapterBean {
private int chapterId = 0;
private String chapterTitle = "";
private int level = 0;
private AdapterBean parent = null; // 父目录节点
private boolean hasChild = false; // 该节点有没有子目录
private boolean showChild = false; // 该节点的子目录有没有显示
private List<AdapterBean> childNodeList = null;
private int visibility = View.GONE; // 该节点有没有显示
public int getChapterId() {
return chapterId;
}
public void setChapterId(int chapterId) {
this.chapterId = chapterId;
}
public String getChapterTitle() {
return chapterTitle;
}
public void setChapterTitle(String chapterTitle) {
this.chapterTitle = chapterTitle;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public AdapterBean getParent() {
return parent;
}
public void setParent(AdapterBean parent) {
this.parent = parent;
}
public boolean getHasChild() {
return hasChild;
}
public void setHasChild(boolean hasChild) {
this.hasChild = hasChild;
}
public boolean getShowChild() {
return showChild;
}
public void setShowChild(boolean showChild) {
this.showChild = showChild;
}
public List<AdapterBean> getChildNodeList() {
return childNodeList;
}
public void setChildNodeList(List<AdapterBean> childNodeList) {
this.childNodeList = childNodeList;
}
public int getVisibility() {
return visibility;
}
public void setVisibility(int visibility) {
this.visibility = visibility;
}
}
所以前面遍历的代码就需要改一下了
MainActivity.java
private void handleList(List<DataBean> dataList) {
if (dataList == null || dataList.getMainChapterList() == null) return;
List<AdapterBean> adapterList = createAdapterList(dataList.getMainChapterList());
adapter.setData(adapterList);
}
private void createAdapterList(List<MainChapterBean> mainChapterList) {
List<AdapterBean> adapterList = new ArrayList<>();
for (int i = 0; i < mainChapterList.size(); i++) {
MainChapterBean item = mainChapterList.get(i);
AdapterBean bean = new AdapterBean();
bean.setChapterId(item.getChapterId);
bean.setChapterTitle(item.getChapterTitle);
bean.setLevel(0);
bean.setParent(null);
bean.setHasChild(item.getSubChapterList() != null && !item.getSubChapterList().isEmpty);
bean.setShowChild(false);
bean.setVisibility(View.VISIBLE); // 第一层目录是默认显示的
adapterList.add(bean);
if (bean.getHasChild()) {
bean.setChildNodeList(new ArrayList<>());
dfs(1, item.getSubChapterList(), adapterList, bean);
}
}
}
private void dfs(int level, List<SubChapterBean> subChapterList, List<AdapterBean> adapterList, AdapterBean parent) {
if (subChapterList == null) return;
for (int i = 0; i < subChapterList.size(); i++) {
SubChapterBean item = subChapterList.get(i);
AdapterBean bean = new AdapterBean();
parent.getChildNodeList().add(bean);
bean.setChapterTitle(item.getChapterTitle());
bean.setChapterId(item.getChapterId());
bean.setLevel(level);
bean.setParent(parent);
bean.setShowChild(false);
node.setHasChild(item.getSubChapterList() != null && !item.getSubChapterList().isEmpty());
node.setVisibility(View.GONE);
adapterList.add(bean);
if (node.getHasChild()) {
node.setChildNodeList(new ArrayList<>());
dfs(level + 1, item.getSubChapterList(), adapterList, bean);
}
}
}
MyAdapter.java
/** 点击了某个有子目录的节点时 显示第一层孩子节点
* @parem position 点击的节点的位置
* @parem bean 点击的节点
*/
public void showNode(int posiiton, AdapterBean bean) {
bean.setShowChild(true);
for (int i = position + 1; i < mAdapterList.size(); i++) {
AdapterBean item = mAdapterList.get(i);
if (item.getParent() == bean) item.setVisibility(View.VISIBLE);
}
notifyDataSetChanged();
}
/** 点击了某个有子目录的节点时 隐藏这个节点下所有层的子目录
* @parem position 点击的节点的位置
* @parem bean 点击的节点
*/
public void hideNode(int position, AdapterBean bean) {
bean.setShowChild(false);
List<AdapterBean> list = bean.getChildNodeList();
for (int i = 0; i < list.size(); i++) {
AdapterBean item = list.get(i);
// 如果这个节点没有子目录或者第一层子目录没有显示的话 那就不用遍历了
if (item.getShowChild() && item.getHasChild()) {
recurseHideNode(item.getChildNodeList());
}
item.setShowChild(false);
item.setVisibility(View.GONE);
}
notifyDataSetChanged();
}
private void recurseHideNode(List<AdapterBean> childList) {
if (childList == null) return;
for (int i = 0; i < childList.size(); i++) {
AdapterBean item = childList.get(i);
if (item.getShowChild() && item.getHasChild()) {
recurseHideNode(item.getChildNodeList());
}
item.setShowChild(false);
item.setVisibility(View.GONE);
}
}