//一.第一种方式 自定义adapter实现:
1.第一步 导入需要用到的依赖库:
//RecyclerView
implementation 'com.android.support:recyclerview-v7:28.0.0'
//RecyclerAdapter
implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.28'
//刷新控件
implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0-alpha-28'
2.第二步 新建BaseTreeRecyclerViewAdapter类:
/**
* @author CJF
*/
public abstract class BaseTreeRecyclerViewAdapter extends RecyclerView.Adapter {
protected Context mContext;
/**
* 默认不展开
*/
private int defaultExpandLevel = 0;
/**
* 展开与关闭的图片
*/
private int iconExpand = -1, iconNoExpand = -1;
/**
* 存储所有的Node
*/
protected List<NodeBean> mAllNodeBeans = new ArrayList<>();
/**
* 存储所有可见的Node
*/
protected List<NodeBean> mNodeBeans = new ArrayList<>();
protected LayoutInflater mInflater;
/**
* 点击的回调接口
*/
private OnTreeClickListener treeClickListener;
public interface OnTreeClickListener {
void onClick(NodeBean nodeBean, int position);
}
/**
* 接口监听
*
* @param treeClickListener
*/
public void setOnTreeClickListener(OnTreeClickListener treeClickListener) {
this.treeClickListener = treeClickListener;
}
/**
* 接口调用
*
* @param nodeBean
* @param position
*/
public void onTreeClickListener(NodeBean nodeBean, int position) {
if (null != treeClickListener) {
treeClickListener.onClick(nodeBean, position);
}
}
public BaseTreeRecyclerViewAdapter(RecyclerView recyclerView, Context context, List<NodeBean> datas,
int defaultExpandLevel, int iconExpand, int iconNoExpand) {
mContext = context;
this.defaultExpandLevel = defaultExpandLevel;
this.iconExpand = iconExpand;
this.iconNoExpand = iconNoExpand;
for (NodeBean nodeBean : datas) {
nodeBean.getChildren().clear();
nodeBean.iconExpand = iconExpand;
nodeBean.iconNoExpand = iconNoExpand;
}
/**
* 对所有的Node进行排序
*/
mAllNodeBeans = TreeHelper.getInstance().getSortedNodes(datas, defaultExpandLevel);
/**
* 过滤出可见的Node
*/
mNodeBeans = TreeHelper.getInstance().filterVisibleNode(mAllNodeBeans);
mInflater = LayoutInflater.from(context);
}
/**
* @param mTree
* @param context
* @param datas
* @param defaultExpandLevel 默认展开几级树
*/
public BaseTreeRecyclerViewAdapter(RecyclerView mTree, Context context, List<NodeBean> datas, int defaultExpandLevel) {
this(mTree, context, datas, defaultExpandLevel, -1, -1);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
NodeBean nodeBean = mNodeBeans.get(position);
// convertView = getConvertView(node, position, convertView, parent);
// 设置内边距
holder.itemView.setPadding(nodeBean.getLevel() * 50, 10, 10, 10);
/**
* 设置节点点击时,可以展开以及关闭,将事件继续往外公布
*/
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
expandOrCollapse(position);
//接口调用
onTreeClickListener(mNodeBeans.get(position), position);
}
});
onBindViewHolder(nodeBean, holder, position);
}
@Override
public int getItemCount() {
return mNodeBeans.size();
}
/**
* 获取排序后所有节点
*
* @return
*/
public List<NodeBean> getAllNodes() {
if (mAllNodeBeans == null) {
mAllNodeBeans = new ArrayList<NodeBean>();
}
return mAllNodeBeans;
}
/**
* 获取所有选中节点
*
* @return
*/
public List<NodeBean> getSelectedNode() {
List<NodeBean> checks = new ArrayList<NodeBean>();
for (int i = 0; i < mAllNodeBeans.size(); i++) {
NodeBean n = mAllNodeBeans.get(i);
if (n.isChecked()) {
checks.add(n);
}
}
return checks;
}
/**
* 相应ListView的点击事件 展开或关闭某节点
*
* @param position
*/
public void expandOrCollapse(int position) {
NodeBean n = mNodeBeans.get(position);
// 排除传入参数错误异常
if (n != null) {
if (!n.isLeaf()) {
n.setExpand(!n.isExpand());
mNodeBeans = TreeHelper.getInstance().filterVisibleNode(mAllNodeBeans);
// 刷新视图
notifyDataSetChanged();
}
}
}
/**
* 设置多选
*
* @param nodeBean
* @param checked
*/
protected void setChecked(final NodeBean nodeBean, boolean checked) {
nodeBean.setChecked(checked);
setChildChecked(nodeBean, checked);
if (nodeBean.getParent() != null) {
setNodeParentChecked(nodeBean.getParent(), checked);
}
notifyDataSetChanged();
}
/**
* 设置是否选中
*
* @param nodeBean
* @param checked
*/
public <T> void setChildChecked(NodeBean<T> nodeBean, boolean checked) {
if (!nodeBean.isLeaf()) {
nodeBean.setChecked(checked);
for (NodeBean childrenNodeBean : nodeBean.getChildren()) {
setChildChecked(childrenNodeBean, checked);
}
} else {
nodeBean.setChecked(checked);
}
}
private void setNodeParentChecked(NodeBean nodeBean, boolean checked) {
if (checked) {
nodeBean.setChecked(checked);
if (nodeBean.getParent() != null) {
setNodeParentChecked(nodeBean.getParent(), checked);
}
} else {
List<NodeBean> childrens = nodeBean.getChildren();
boolean isChecked = false;
for (NodeBean children : childrens) {
if (children.isChecked()) {
isChecked = true;
}
}
//如果所有自节点都没有被选中 父节点也不选中
if (!isChecked) {
nodeBean.setChecked(checked);
}
if (nodeBean.getParent() != null) {
setNodeParentChecked(nodeBean.getParent(), checked);
}
}
}
/**
* 清除掉之前数据并刷新 重新添加
*
* @param mlists
* @param defaultExpandLevel 默认展开几级列表
*/
public void addDataAll(List<NodeBean> mlists, int defaultExpandLevel) {
mAllNodeBeans.clear();
addData(-1, mlists, defaultExpandLevel);
}
/**
* 在指定位置添加数据并刷新 可指定刷新后显示层级
*
* @param index
* @param mlists
* @param defaultExpandLevel 默认展开几级列表
*/
public void addData(int index, List<NodeBean> mlists, int defaultExpandLevel) {
this.defaultExpandLevel = defaultExpandLevel;
notifyData(index, mlists);
}
/**
* 在指定位置添加数据并刷新
*
* @param index
* @param mlists
*/
public void addData(int index, List<NodeBean> mlists) {
notifyData(index, mlists);
}
/**
* 添加数据并刷新
*
* @param mlists
*/
public void addData(List<NodeBean> mlists) {
addData(mlists, defaultExpandLevel);
}
/**
* 添加数据并刷新 可指定刷新后显示层级
*
* @param mlists
* @param defaultExpandLevel
*/
public void addData(List<NodeBean> mlists, int defaultExpandLevel) {
this.defaultExpandLevel = defaultExpandLevel;
notifyData(-1, mlists);
}
/**
* 添加数据并刷新
*
* @param nodeBean
*/
public void addData(NodeBean nodeBean) {
addData(nodeBean, defaultExpandLevel);
}
/**
* 添加数据并刷新 可指定刷新后显示层级
*
* @param nodeBean
* @param defaultExpandLevel
*/
public void addData(NodeBean nodeBean, int defaultExpandLevel) {
List<NodeBean> nodeBeans = new ArrayList<>();
nodeBeans.add(nodeBean);
this.defaultExpandLevel = defaultExpandLevel;
notifyData(-1, nodeBeans);
}
/**
* 刷新数据
*
* @param index
* @param mListNodeBeans
*/
private void notifyData(int index, List<NodeBean> mListNodeBeans) {
for (int i = 0; i < mListNodeBeans.size(); i++) {
NodeBean nodeBean = mListNodeBeans.get(i);
nodeBean.getChildren().clear();
nodeBean.iconExpand = iconExpand;
nodeBean.iconNoExpand = iconNoExpand;
}
for (int i = 0; i < mAllNodeBeans.size(); i++) {
NodeBean nodeBean = mAllNodeBeans.get(i);
nodeBean.getChildren().clear();
// node.isNewAdd = false;
}
if (index != -1) {
mAllNodeBeans.addAll(index, mListNodeBeans);
} else {
mAllNodeBeans.addAll(mListNodeBeans);
}
/**
* 对所有的Node进行排序
*/
mAllNodeBeans = TreeHelper.getInstance().getSortedNodes(mAllNodeBeans, defaultExpandLevel);
/**
* 过滤出可见的Node
*/
mNodeBeans = TreeHelper.getInstance().filterVisibleNode(mAllNodeBeans);
//刷新数据
notifyDataSetChanged();
}
public abstract void onBindViewHolder(NodeBean nodeBean, RecyclerView.ViewHolder holder, final int position);
}
3.第三步 新建TreeRecyclerViewAdapter类:
/**
* @author CJF
*/
public class TreeRecyclerViewAdapter extends BaseTreeRecyclerViewAdapter {
//选中的回调接口
private OnTreeCheckedChangeListener checkedChangeListener;
public interface OnTreeCheckedChangeListener {
void onCheckChange(NodeBean nodeBean, int position, boolean isChecked);
}
/**
* 接口监听
*
* @param checkedChangeListener
*/
public void setTreeCheckedChangeListener(OnTreeCheckedChangeListener checkedChangeListener) {
this.checkedChangeListener = checkedChangeListener;
}
/**
* 接口调用
*
* @param nodeBean
* @param position
* @param isChecked
*/
public void onTreeCheckedChangeListener(NodeBean nodeBean, int position, boolean isChecked) {
if (null != checkedChangeListener) {
checkedChangeListener.onCheckChange(nodeBean, position, isChecked);
}
}
public TreeRecyclerViewAdapter(RecyclerView recyclerView, Context context, List<NodeBean> datas, int defaultExpandLevel, int iconExpand, int iconNoExpand) {
super(recyclerView, context, datas, defaultExpandLevel, iconExpand, iconNoExpand);
}
public TreeRecyclerViewAdapter(RecyclerView mTree, Context context, List<NodeBean> datas, int defaultExpandLevel) {
super(mTree, context, datas, defaultExpandLevel);
}
@Override
public void onBindViewHolder(final NodeBean nodeBean, final RecyclerView.ViewHolder holder, final int position) {
final ViewHolder viewHolder = (ViewHolder) holder;
viewHolder.mTreeHeaderName.setText(nodeBean.getName());
if (nodeBean.getIcon() == -1) {
viewHolder.mTreeHeaderExpand.setVisibility(View.INVISIBLE);
} else {
viewHolder.mTreeHeaderExpand.setVisibility(View.VISIBLE);
viewHolder.mTreeHeaderExpand.setImageResource(nodeBean.getIcon());
}
viewHolder.mTreeHeaderCheckBox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setChecked(nodeBean, viewHolder.mTreeHeaderCheckBox.isChecked());
//接口调用
onTreeCheckedChangeListener(nodeBean, position, viewHolder.mTreeHeaderCheckBox.isChecked());
}
});
if (nodeBean.isChecked()) {
viewHolder.mTreeHeaderCheckBox.setChecked(true);
} else {
viewHolder.mTreeHeaderCheckBox.setChecked(false);
}
}
@NotNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NotNull ViewGroup parent, int viewType) {
View inflate = View.inflate(mContext, R.layout.tree_header_item, null);
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
inflate.setLayoutParams(params);
return new ViewHolder(inflate);
}
static class ViewHolder extends RecyclerView.ViewHolder {
private CheckBox mTreeHeaderCheckBox;
private TextView mTreeHeaderName;
private ImageView mTreeHeaderExpand;
public ViewHolder(View itemView) {
super(itemView);
mTreeHeaderCheckBox = itemView.findViewById(R.id.mTreeHeaderCheckBox);
mTreeHeaderName = itemView.findViewById(R.id.mTreeHeaderName);
mTreeHeaderExpand = itemView.findViewById(R.id.mTreeHeaderExpand);
}
}
}
4.第四步 新建TreeHelper工具类:
/**
* @author CJF
*/
public class TreeHelper {
private volatile static TreeHelper treeHelper = null;
public static TreeHelper getInstance() {
if (null == treeHelper) {
synchronized (TreeHelper.class) {
if (null == treeHelper) {
treeHelper = new TreeHelper();
}
}
}
return treeHelper;
}
/**
* 传入node 返回排序后的Node
* 拿到用户传入的数据,转化为List<Node>以及设置Node间关系,然后根节点,从根往下遍历进行排序;
*
* @param datas
* @param defaultExpandLevel 默认显示
* @return
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
public List<NodeBean> getSortedNodes(List<NodeBean> datas, int defaultExpandLevel) {
List<NodeBean> result = new ArrayList<NodeBean>();
// 设置Node间父子关系
List<NodeBean> nodeBeans = convetData2Node(datas);
// 拿到根节点
List<NodeBean> rootNodeBeans = getRootNodes(nodeBeans);
// 排序以及设置Node间关系
for (NodeBean nodeBean : rootNodeBeans) {
addNode(result, nodeBean, defaultExpandLevel, 1);
}
return result;
}
/**
* 过滤出所有可见的Node
* 过滤Node的代码很简单,遍历所有的Node,只要是根节点或者父节点是展开状态就添加返回
*
* @param nodeBeans
* @return
*/
public List<NodeBean> filterVisibleNode(List<NodeBean> nodeBeans) {
List<NodeBean> result = new ArrayList<NodeBean>();
for (NodeBean nodeBean : nodeBeans) {
// 如果为跟节点,或者上层目录为展开状态
if (nodeBean.isRootNode() || nodeBean.isParentExpand()) {
setNodeIcon(nodeBean);
result.add(nodeBean);
}
}
return result;
}
/**
* 将我们的数据转化为树的节点
* 设置Node间,父子关系;让每两个节点都比较一次,即可设置其中的关系
*/
private List<NodeBean> convetData2Node(List<NodeBean> nodeBeans) {
for (int i = 0; i < nodeBeans.size(); i++) {
NodeBean n = nodeBeans.get(i);
for (int j = i + 1; j < nodeBeans.size(); j++) {
NodeBean m = nodeBeans.get(j);
if (m.getPid() != null) {
//n时m的父节点
if (m.getPid().equals(n.getId())) {
n.getChildren().add(m);
m.setParent(n);
//m时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 nodeBeans;
}
/**
* 获得根节点
*
* @param nodeBeans
* @return
*/
private List<NodeBean> getRootNodes(List<NodeBean> nodeBeans) {
List<NodeBean> root = new ArrayList<NodeBean>();
for (NodeBean nodeBean : nodeBeans) {
if (nodeBean.isRootNode()) {
root.add(nodeBean);
}
}
return root;
}
/**
* 把一个节点上的所有的内容都挂上去
* 通过递归的方式,把一个节点上的所有的子节点等都按顺序放入
*/
private <T> void addNode(List<NodeBean> nodeBeans, NodeBean<T> nodeBean, int defaultExpandLeval, int currentLevel) {
nodeBeans.add(nodeBean);
if (defaultExpandLeval >= currentLevel) {
nodeBean.setExpand(true);
}
if (nodeBean.isLeaf()) {
return;
}
for (int i = 0; i < nodeBean.getChildren().size(); i++) {
addNode(nodeBeans, nodeBean.getChildren().get(i), defaultExpandLeval, currentLevel + 1);
}
}
/**
* 设置节点的图标
*
* @param nodeBean
*/
private void setNodeIcon(NodeBean nodeBean) {
if (nodeBean.getChildren().size() > 0 && nodeBean.isExpand()) {
nodeBean.setIcon(nodeBean.iconExpand);
} else if (nodeBean.getChildren().size() > 0 && !nodeBean.isExpand()) {
nodeBean.setIcon(nodeBean.iconNoExpand);
} else {
nodeBean.setIcon(-1);
}
}
}
5.第五步 新建NodeBean类:
/**
* @author CJF
*/
public class NodeBean<T> {
/**
* 当前节点id
*/
private String id;
/**
* 父节点id
*/
private String pid;
/**
* 节点数据实体类
*/
private T data;
/**
* 设置开启 关闭的图片
*/
public int iconExpand = -1, iconNoExpand = -1;
/**
* 节点名称
*/
private String name;
/**
* 当前的级别
*/
private int level;
/**
* 是否展开
*/
private boolean isExpand = false;
private int icon = -1;
/**
* 下一级的子Node
*/
private List<NodeBean> children = new ArrayList<>();
/**
* 父Node
*/
private NodeBean parent;
/**
* 是否被checked选中
*/
private boolean isChecked;
public NodeBean() {
}
public NodeBean(String id, String pid, String name) {
this.id = id;
this.pid = pid;
this.name = name;
}
public NodeBean(String id, String pid, T data, String name) {
this.id = id;
this.pid = pid;
this.data = data;
this.name = name;
}
/**
* 是否为根节点
*
* @return
*/
public boolean isRootNode() {
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 (NodeBean nodeBean : children) {
nodeBean.setExpand(isExpand);
}
}
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPid() {
return pid;
}
public void setPid(String pid) {
this.pid = pid;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public int getIconExpand() {
return iconExpand;
}
public void setIconExpand(int iconExpand) {
this.iconExpand = iconExpand;
}
public int getIconNoExpand() {
return iconNoExpand;
}
public void setIconNoExpand(int iconNoExpand) {
this.iconNoExpand = iconNoExpand;
}
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 int getIcon() {
return icon;
}
public void setIcon(int icon) {
this.icon = icon;
}
public List<NodeBean> getChildren() {
return children;
}
public void setChildren(List<NodeBean> children) {
this.children = children;
}
public NodeBean getParent() {
return parent;
}
public void setParent(NodeBean parent) {
this.parent = parent;
}
public boolean isChecked() {
return isChecked;
}
public void setChecked(boolean checked) {
isChecked = checked;
}
}
6.第六步 新建TreeHeaderView自定义View类:
/**
* @author CJF
*/
public class TreeHeaderView extends LinearLayout {
private TreeRecyclerViewAdapter adapter;
private List<NodeBean> dataList = new ArrayList<>();
public TreeHeaderView(Context context) {
super(context);
initView(context);
initData();
}
public TreeHeaderView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initView(context);
initData();
}
public TreeHeaderView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
initData();
}
private void initView(Context context) {
//树结构布局
View headerLayout = LayoutInflater.from(context).inflate(R.layout.tree_header_layout, this, true);
// LinearLayoutManager manager = new LinearLayoutManager(context);
//禁止滑动 布局管理器
LinearLayoutManager manager = new LinearLayoutManager(context) {
//禁止竖向滑动 RecyclerView 为垂直状态(VERTICAL)
@Override
public boolean canScrollVertically() {
return false;
}
//禁止横向滑动 RecyclerView 为水平状态(HORIZONTAL)
/*@Override
public boolean canScrollHorizontally() {
return false;
}*/
};
RecyclerView mTreeHeaderViewRecy = headerLayout.findViewById(R.id.mTreeHeaderViewRecy);
mTreeHeaderViewRecy.setLayoutManager(manager);
//第一个参数 ListView & RecyclerView
//第二个参数 上下文
//第三个参数 数据集
//第四个参数 默认展开层级数 0为不展开
//第五个参数 展开的图标
//第六个参数 闭合的图标
adapter = new TreeRecyclerViewAdapter(mTreeHeaderViewRecy, context, dataList, 0, R.drawable.svg_expand_more, R.drawable.svg_navigate_next);
mTreeHeaderViewRecy.setAdapter(adapter);
}
private void initData() {
//根节点0 1 2
dataList.add(new NodeBean<>("0", "-1", "A 1级节点"));
dataList.add(new NodeBean<>("1", "-1", "B 1级节点"));
dataList.add(new NodeBean<>("2", "-1", "C 1级节点"));
// //根节点1的二级节点
dataList.add(new NodeBean<>("3", "0", "A 2级节点"));
dataList.add(new NodeBean<>("4", "0", "A 2级节点"));
dataList.add(new NodeBean<>("5", "0", "A 2级节点"));
//根节点2的二级节点
dataList.add(new NodeBean<>("6", "1", "B 2级节点"));
dataList.add(new NodeBean<>("7", "1", "B 2级节点"));
dataList.add(new NodeBean<>("8", "1", "B 2级节点"));
//根节点3的二级节点
dataList.add(new NodeBean<>("9", "2", "C 2级节点"));
dataList.add(new NodeBean<>("10", "2", "C 2级节点"));
dataList.add(new NodeBean<>("11", "2", "C 2级节点"));
//三级节点
dataList.add(new NodeBean<>("12", "3", "A 3级节点"));
dataList.add(new NodeBean<>("13", "3", "A 3级节点"));
dataList.add(new NodeBean<>("14", "3", "A 3级节点"));
dataList.add(new NodeBean<>("15", "4", "A 3级节点"));
dataList.add(new NodeBean<>("16", "4", "A 3级节点"));
dataList.add(new NodeBean<>("17", "4", "A 3级节点"));
dataList.add(new NodeBean<>("18", "5", "A 3级节点"));
dataList.add(new NodeBean<>("19", "5", "A 3级节点"));
dataList.add(new NodeBean<>("20", "5", "A 3级节点"));
//四级节点
dataList.add(new NodeBean<>("21", "12", "A 4级节点"));
//五级节点
dataList.add(new NodeBean<>("22", "21", "A 5级节点"));
//六级节点
dataList.add(new NodeBean<>("23", "22", "A 6级节点"));
//七级节点
dataList.add(new NodeBean<>("24", "23", "A 7级节点"));
//八级节点
dataList.add(new NodeBean<>("25", "24", "A 8级节点"));
adapter.addData(dataList);
// //获取所有节点
// final List<Node> allNodes = mAdapter.getAllNodes();
// for (Node allNode : allNodes) {
// Log.e("TAG1231", "onCreate: " + allNode.getName());
// }
//选中状态监听
adapter.setTreeCheckedChangeListener(new TreeRecyclerViewAdapter.OnTreeCheckedChangeListener() {
@Override
public void onCheckChange(NodeBean nodeBean, int position, boolean isChecked) {
Log.e("TAG1231", "onCheckChange position: " + nodeBean.getName());
//获取所有选中节点
List<NodeBean> selectedNodeBean = adapter.getSelectedNode();
StringBuilder builder = new StringBuilder();
for (NodeBean n : selectedNodeBean) {
builder.append(n.getName()).append("\n");
}
Log.e("TAG1231", "builder: " + builder);
}
});
//总item点击状态监听
adapter.setOnTreeClickListener(new BaseTreeRecyclerViewAdapter.OnTreeClickListener() {
@Override
public void onClick(NodeBean nodeBean, int position) {
Log.e("TAG1231", "setOnTreeClickListener: " + nodeBean.getName());
}
});
}
}
7.第七步 新建TreeListAdapter适配器类适配普通列表数据:
/**
* @author CJF
*/
public class TreeListAdapter extends BaseQuickAdapter<String, BaseViewHolder> {
public TreeListAdapter(int layoutResId) {
super(layoutResId);
}
@Override
protected void convert(BaseViewHolder helper, String item) {
helper.setText(R.id.mOppoSdkTextPosition, String.valueOf(helper.getAdapterPosition()));
helper.setText(R.id.mOppoSdkText, item);
}
}
8.第八步 新建TreeListActivity页面放入头布局和普通数据:
/**
* @author CJF
*/
public class TreeListActivity extends AppCompatActivity {
private final LinearLayoutManager manager = new LinearLayoutManager(this);
private final TreeListAdapter adapter=new TreeListAdapter(R.layout.sdk_item);
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tree_list);
RecyclerView mTreeListRecy = findViewById(R.id.mTreeListRecy);
mTreeListRecy.setLayoutManager(manager);
mTreeListRecy.setAdapter(adapter);
TreeHeaderView treeHeaderView = new TreeHeaderView(this);
adapter.addHeaderView(treeHeaderView);
ArrayList<String> list = new ArrayList<>();
for (int i = 0; i < 30; i++) {
list.add("数据"+i);
}
adapter.addData(list);
}
}
//manifest别忘记注册activity:
<activity
android:name=".phone.activity.TreeListActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:windowSoftInputMode="stateHidden"
tools:ignore="LockedOrientationActivity" />
9.第九步 各个xml布局文件:
//activity_tree_list:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@color/color_white"
android:orientation="vertical">
<com.scwang.smartrefresh.layout.SmartRefreshLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:srlEnableLoadMore="true"
app:srlEnableRefresh="true">
<android.support.v7.widget.RecyclerView
android:id="@+id/mTreeListRecy"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.scwang.smartrefresh.layout.footer.FalsifyFooter
android:layout_width="match_parent"
android:layout_height="@dimen/dp_50" />
<com.scwang.smartrefresh.layout.header.FalsifyHeader
android:layout_width="match_parent"
android:layout_height="@dimen/dp_50" />
</com.scwang.smartrefresh.layout.SmartRefreshLayout>
</LinearLayout>
//sdk_item:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/dp_5"
android:layout_marginLeft="@dimen/dp_20"
android:layout_marginRight="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_5"
android:background="@drawable/selector_common_item"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:id="@+id/mOppoSdkTextPosition"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:background="@drawable/selector_common_item"
android:gravity="center"
android:minHeight="@dimen/dp_50"
android:padding="@dimen/dp_10"
android:text="0"
android:textColor="@color/black"
android:textSize="@dimen/sp_15" />
<TextView
android:id="@+id/mOppoSdkText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="8"
android:background="@drawable/selector_common_item"
android:gravity="left|center_vertical"
android:minHeight="@dimen/dp_50"
android:padding="@dimen/dp_10"
android:text="text"
android:textColor="@color/black"
android:textSize="@dimen/sp_15" />
</LinearLayout>
//tree_header_layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/color_white"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="@+id/mTreeHeaderViewRecy"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
//tree_header_item:
?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/dp_5"
android:layout_marginLeft="@dimen/dp_20"
android:layout_marginRight="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_5"
android:gravity="center"
android:orientation="horizontal">
<ImageView
android:src="@drawable/svg_navigate_next"
android:id="@+id/mTreeHeaderExpand"
android:layout_width="@dimen/dp_50"
android:layout_height="@dimen/dp_50"
android:gravity="center"
android:padding="@dimen/dp_10" />
<CheckBox
android:id="@+id/mTreeHeaderCheckBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/mTreeHeaderName"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="left|center_vertical"
android:minHeight="@dimen/dp_50"
android:padding="@dimen/dp_10"
android:text="text"
android:textColor="@color/black"
android:textSize="@dimen/sp_15" />
</LinearLayout>
10.第十步 两个svg的xml图片文件:
//svg_expand_more:
<vector android:alpha="0.85" android:autoMirrored="true"
android:height="24dp" android:tint="#3B76EC"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#ffffffff" android:pathData="M16.59,8.59L12,13.17 7.41,8.59 6,10l6,6 6,-6z"/>
</vector>
//svg_navigate_next:
<vector android:alpha="0.85" android:autoMirrored="true"
android:height="24dp" android:tint="#3B76EC"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#ffffffff" android:pathData="M10,6L8.59,7.41 13.17,12l-4.58,4.59L10,18l6,-6z"/>
</vector>
//二.第二种方式使用BaseQuickAdapter库实现无限层级树结构,代码更简便:
1.第一步 导入依赖库:
//RecyclerView
implementation 'com.android.support:recyclerview-v7:28.0.0'
//RecyclerAdapter
implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.28'
2.第二步 新建Tree2ListActivity页面代码如下:
/**
* @author CJF
*/
public class Tree2ListActivity extends AppCompatActivity {
private final LinearLayoutManager manager = new LinearLayoutManager(this);
private final TreeListAdapter adapter = new TreeListAdapter(R.layout.sdk_item);
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tree_list);
RecyclerView mTreeListRecy = findViewById(R.id.mTreeListRecy);
mTreeListRecy.setLayoutManager(manager);
mTreeListRecy.setAdapter(adapter);
Tree2HeaderView tree2HeaderView = new Tree2HeaderView(this);
adapter.addHeaderView(tree2HeaderView);
ArrayList<String> list = new ArrayList<>();
for (int i = 0; i < 30; i++) {
list.add("数据" + i);
}
adapter.addData(list);
}
//manifest注册:
<activity
android:name=".phone.activity.Tree2ListActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:windowSoftInputMode="stateHidden"
tools:ignore="LockedOrientationActivity" />
3.第三步 新建TreeListAdapter普通数据适配器:
/**
* @author CJF
*/
public class TreeListAdapter extends BaseQuickAdapter<String, BaseViewHolder> {
public TreeListAdapter(int layoutResId) {
super(layoutResId);
}
@Override
protected void convert(BaseViewHolder helper, String item) {
helper.setText(R.id.mOppoSdkTextPosition, String.valueOf(helper.getAdapterPosition()));
helper.setText(R.id.mOppoSdkText, item);
}
}
4.第四步 新建Tree2HeaderView 自定义view 头布局:
/**
* @author CJF
*/
public class Tree2HeaderView extends LinearLayout implements BaseQuickAdapter.OnItemClickListener {
private final Tree2HeaderAdapter adapter=new Tree2HeaderAdapter(R.layout.tree_header_item);
private List<NodeBean> mAllNodeBeans;
private List<NodeBean> mNodeBeans;
public Tree2HeaderView(Context context) {
super(context);
initView(context);
initData();
}
public Tree2HeaderView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initView(context);
initData();
}
public Tree2HeaderView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
initData();
}
private void initView(Context context) {
//树结构布局
View headerLayout = LayoutInflater.from(context).inflate(R.layout.tree_header_layout, this, true);
// LinearLayoutManager manager = new LinearLayoutManager(context);
//禁止滑动 布局管理器
LinearLayoutManager manager = new LinearLayoutManager(context) {
//禁止竖向滑动 RecyclerView 为垂直状态(VERTICAL)
@Override
public boolean canScrollVertically() {
return false;
}
//禁止横向滑动 RecyclerView 为水平状态(HORIZONTAL)
/*@Override
public boolean canScrollHorizontally() {
return false;
}*/
};
RecyclerView mTreeHeaderViewRecy = headerLayout.findViewById(R.id.mTreeHeaderViewRecy);
mTreeHeaderViewRecy.setLayoutManager(manager);
mTreeHeaderViewRecy.setAdapter(adapter);
adapter.setOnItemClickListener(this);
}
private void initData() {
List<NodeBean> maxDataList = new ArrayList<>();
//根节点0 1 2
maxDataList.add(new NodeBean<>("0", "-1", "A 1级节点"));
maxDataList.add(new NodeBean<>("1", "-1", "B 1级节点"));
maxDataList.add(new NodeBean<>("2", "-1", "C 1级节点"));
// //根节点1的二级节点
maxDataList.add(new NodeBean<>("3", "0", "A 2级节点"));
maxDataList.add(new NodeBean<>("4", "0", "A 2级节点"));
maxDataList.add(new NodeBean<>("5", "0", "A 2级节点"));
//根节点2的二级节点
maxDataList.add(new NodeBean<>("6", "1", "B 2级节点"));
maxDataList.add(new NodeBean<>("7", "1", "B 2级节点"));
maxDataList.add(new NodeBean<>("8", "1", "B 2级节点"));
//根节点3的二级节点
maxDataList.add(new NodeBean<>("9", "2", "C 2级节点"));
maxDataList.add(new NodeBean<>("10", "2", "C 2级节点"));
maxDataList.add(new NodeBean<>("11", "2", "C 2级节点"));
//三级节点
maxDataList.add(new NodeBean<>("12", "3", "A 3级节点"));
maxDataList.add(new NodeBean<>("13", "3", "A 3级节点"));
maxDataList.add(new NodeBean<>("14", "3", "A 3级节点"));
maxDataList.add(new NodeBean<>("15", "4", "A 3级节点"));
maxDataList.add(new NodeBean<>("16", "4", "A 3级节点"));
maxDataList.add(new NodeBean<>("17", "4", "A 3级节点"));
maxDataList.add(new NodeBean<>("18", "5", "A 3级节点"));
maxDataList.add(new NodeBean<>("19", "5", "A 3级节点"));
maxDataList.add(new NodeBean<>("20", "5", "A 3级节点"));
//四级节点
maxDataList.add(new NodeBean<>("21", "12", "A 4级节点"));
//五级节点
maxDataList.add(new NodeBean<>("22", "21", "A 5级节点"));
//六级节点
maxDataList.add(new NodeBean<>("23", "22", "A 6级节点"));
//七级节点
maxDataList.add(new NodeBean<>("24", "23", "A 7级节点"));
//八级节点
maxDataList.add(new NodeBean<>("25", "24", "A 8级节点"));
maxDataList.add(new NodeBean<>("26", "25", "A 9级节点"));
maxDataList.add(new NodeBean<>("27", "26", "A 10级节点"));
maxDataList.add(new NodeBean<>("28", "27", "A 11级节点"));
maxDataList.add(new NodeBean<>("29", "28", "A 12级节点"));
maxDataList.add(new NodeBean<>("30", "29", "A 13级节点"));
maxDataList.add(new NodeBean<>("31", "30", "A 14级节点"));
maxDataList.add(new NodeBean<>("32", "31", "A 15级节点"));
maxDataList.add(new NodeBean<>("33", "32", "A 16级节点"));
maxDataList.add(new NodeBean<>("34", "33", "A 17级节点"));
maxDataList.add(new NodeBean<>("35", "-1", "D 1级节点"));
maxDataList.add(new NodeBean<>("36", "-1", "E 1级节点"));
maxDataList.add(new NodeBean<>("37", "-1", "F 1级节点"));
maxDataList.add(new NodeBean<>("38", "35", "D 2级节点"));
maxDataList.add(new NodeBean<>("39", "36", "E 2级节点"));
maxDataList.add(new NodeBean<>("40", "37", "F 2级节点"));
/**
* 对所有的Node进行排序
*/
mAllNodeBeans = TreeHelper.getInstance().getSortedNodes(maxDataList, 0);
/**
* 过滤出可见的Node
*/
mNodeBeans = TreeHelper.getInstance().filterVisibleNode(mAllNodeBeans);
adapter.addData(mNodeBeans);
// //获取所有节点
// final List<Node> allNodes = mAdapter.getAllNodes();
// for (Node allNode : allNodes) {
// Log.e("TAG1231", "onCreate: " + allNode.getName());
// }
}
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
expandOrCollapse(adapter,position);
}
/**
* 相应ListView的点击事件 展开或关闭某节点
*
* @param position
*/
public void expandOrCollapse(BaseQuickAdapter adapter,int position) {
NodeBean n = (NodeBean) adapter.getData().get(position);
// 排除传入参数错误异常
if (n != null) {
if (!n.isLeaf()) {
n.setExpand(!n.isExpand());
mNodeBeans = TreeHelper.getInstance().filterVisibleNode(mAllNodeBeans);
//替换视图
adapter.replaceData(mNodeBeans);
}
}
}
}
5.第五步 新建Tree2HeaderAdapter 适配器,适配树结构数据:
public class Tree2HeaderAdapter extends BaseQuickAdapter<NodeBean, BaseViewHolder> {
public Tree2HeaderAdapter(int layoutResId) {
super(layoutResId);
}
@Override
protected void convert(BaseViewHolder helper, NodeBean item) {
//最大展开8级宽度距离
int level = Math.min(item.getLevel(), 8);
// 设置内边距
helper.itemView.setPadding(level * 50, 10, 10, 10);
//设置文字内容
helper.setText(R.id.mTreeHeaderName, item.getName());
//设置展开与收起的图片
helper.setImageResource(R.id.mTreeHeaderExpand, item.isExpand() ? R.drawable.svg_expand_more : R.drawable.svg_navigate_next);
//图片显示隐藏
helper.setVisible(R.id.mTreeHeaderExpand, item.getChildren().size() > 0);
}
}
6.第六步 新建TreeHelper工具类:
/**
* @author CJF
*/
public class TreeHelper {
private volatile static TreeHelper treeHelper = null;
public static TreeHelper getInstance() {
if (null == treeHelper) {
synchronized (TreeHelper.class) {
if (null == treeHelper) {
treeHelper = new TreeHelper();
}
}
}
return treeHelper;
}
/**
* 传入node 返回排序后的Node
* 拿到用户传入的数据,转化为List<Node>以及设置Node间关系,然后根节点,从根往下遍历进行排序;
*
* @param datas
* @param defaultExpandLevel 默认显示
* @return
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
public List<NodeBean> getSortedNodes(List<NodeBean> datas, int defaultExpandLevel) {
List<NodeBean> result = new ArrayList<NodeBean>();
// 设置Node间父子关系
List<NodeBean> nodeBeans = convetData2Node(datas);
// 拿到根节点
List<NodeBean> rootNodeBeans = getRootNodes(nodeBeans);
// 排序以及设置Node间关系
for (NodeBean nodeBean : rootNodeBeans) {
addNode(result, nodeBean, defaultExpandLevel, 1);
}
return result;
}
/**
* 过滤出所有可见的Node
* 过滤Node的代码很简单,遍历所有的Node,只要是根节点或者父节点是展开状态就添加返回
*
* @param nodeBeans
* @return
*/
public List<NodeBean> filterVisibleNode(List<NodeBean> nodeBeans) {
List<NodeBean> result = new ArrayList<NodeBean>();
for (NodeBean nodeBean : nodeBeans) {
// 如果为跟节点,或者上层目录为展开状态
if (nodeBean.isRootNode() || nodeBean.isParentExpand()) {
setNodeIcon(nodeBean);
result.add(nodeBean);
}
}
return result;
}
/**
* 将我们的数据转化为树的节点
* 设置Node间,父子关系;让每两个节点都比较一次,即可设置其中的关系
*/
public List<NodeBean> convetData2Node(List<NodeBean> nodeBeans) {
for (int i = 0; i < nodeBeans.size(); i++) {
NodeBean n = nodeBeans.get(i);
for (int j = i + 1; j < nodeBeans.size(); j++) {
NodeBean m = nodeBeans.get(j);
if (m.getPid() != null) {
//n时m的父节点
if (m.getPid().equals(n.getId())) {
n.getChildren().add(m);
m.setParent(n);
//m时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 nodeBeans;
}
/**
* 获得根节点
*
* @param nodeBeans
* @return
*/
public List<NodeBean> getRootNodes(List<NodeBean> nodeBeans) {
List<NodeBean> root = new ArrayList<NodeBean>();
for (NodeBean nodeBean : nodeBeans) {
if (nodeBean.isRootNode()) {
root.add(nodeBean);
}
}
return root;
}
/**
* 把一个节点上的所有的内容都挂上去
* 通过递归的方式,把一个节点上的所有的子节点等都按顺序放入
*/
public <T> void addNode(List<NodeBean> nodeBeans, NodeBean<T> nodeBean, int defaultExpandLeval, int currentLevel) {
nodeBeans.add(nodeBean);
if (defaultExpandLeval >= currentLevel) {
nodeBean.setExpand(true);
}
if (nodeBean.isLeaf()) {
return;
}
for (int i = 0; i < nodeBean.getChildren().size(); i++) {
addNode(nodeBeans, nodeBean.getChildren().get(i), defaultExpandLeval, currentLevel + 1);
}
}
/**
* 设置节点的图标
*
* @param nodeBean
*/
private void setNodeIcon(NodeBean nodeBean) {
if (nodeBean.getChildren().size() > 0 && nodeBean.isExpand()) {
nodeBean.setIcon(nodeBean.iconExpand);
} else if (nodeBean.getChildren().size() > 0 && !nodeBean.isExpand()) {
nodeBean.setIcon(nodeBean.iconNoExpand);
} else {
nodeBean.setIcon(-1);
}
}
}
7.第七步 新建NodeBean类:
/**
* @author CJF
*/
public class NodeBean<T> {
/**
* 当前节点id
*/
private String id;
/**
* 父节点id
*/
private String pid;
/**
* 节点数据实体类
*/
private T data;
/**
* 设置开启 关闭的图片
*/
public int iconExpand = -1, iconNoExpand = -1;
/**
* 节点名称
*/
private String name;
/**
* 当前的级别
*/
private int level;
/**
* 是否展开
*/
private boolean isExpand = false;
private int icon = -1;
/**
* 下一级的子Node
*/
private List<NodeBean> children = new ArrayList<>();
/**
* 父Node
*/
private NodeBean parent;
/**
* 是否被checked选中
*/
private boolean isChecked;
public NodeBean() {
}
public NodeBean(String id, String pid, String name) {
this.id = id;
this.pid = pid;
this.name = name;
}
public NodeBean(String id, String pid, T data, String name) {
this.id = id;
this.pid = pid;
this.data = data;
this.name = name;
}
/**
* 是否为根节点
*
* @return
*/
public boolean isRootNode() {
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 (NodeBean nodeBean : children) {
nodeBean.setExpand(isExpand);
}
}
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPid() {
return pid;
}
public void setPid(String pid) {
this.pid = pid;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public int getIconExpand() {
return iconExpand;
}
public void setIconExpand(int iconExpand) {
this.iconExpand = iconExpand;
}
public int getIconNoExpand() {
return iconNoExpand;
}
public void setIconNoExpand(int iconNoExpand) {
this.iconNoExpand = iconNoExpand;
}
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 int getIcon() {
return icon;
}
public void setIcon(int icon) {
this.icon = icon;
}
public List<NodeBean> getChildren() {
return children;
}
public void setChildren(List<NodeBean> children) {
this.children = children;
}
public NodeBean getParent() {
return parent;
}
public void setParent(NodeBean parent) {
this.parent = parent;
}
public boolean isChecked() {
return isChecked;
}
public void setChecked(boolean checked) {
isChecked = checked;
}
}
8.第八步 新建各个需要用到的xml布局文件:
//activity_tree_list:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@color/color_white"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="@+id/mTreeListRecy"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
//sdk_item:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/dp_5"
android:layout_marginLeft="@dimen/dp_20"
android:layout_marginRight="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_5"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:id="@+id/mOppoSdkTextPosition"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:gravity="center"
android:minHeight="@dimen/dp_50"
android:padding="@dimen/dp_10"
android:text="0"
android:textColor="@color/black"
android:textSize="@dimen/sp_15" />
<TextView
android:id="@+id/mOppoSdkText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="8"
android:gravity="left|center_vertical"
android:minHeight="@dimen/dp_50"
android:padding="@dimen/dp_10"
android:text="text"
android:textColor="@color/black"
android:textSize="@dimen/sp_15" />
</LinearLayout>
//tree_header_layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/color_white"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="@+id/mTreeHeaderViewRecy"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
//tree_header_item:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/dp_5"
android:layout_marginLeft="@dimen/dp_20"
android:layout_marginRight="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_5"
android:orientation="vertical">
<LinearLayout
android:id="@+id/mTreeHeaderLin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<ImageView
android:id="@+id/mTreeHeaderExpand"
android:layout_width="@dimen/dp_50"
android:layout_height="@dimen/dp_50"
android:gravity="center"
android:padding="@dimen/dp_10"
android:src="@drawable/svg_navigate_next" />
<TextView
android:id="@+id/mTreeHeaderName"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:gravity="left|center_vertical"
android:maxLines="1"
android:minHeight="@dimen/dp_50"
android:padding="@dimen/dp_10"
android:text="text"
android:textColor="@color/black"
android:textSize="@dimen/sp_15" />
</LinearLayout>
</LinearLayout>
9.第九步 两个svg的xml图片文件:
//svg_expand_more:
<vector android:alpha="0.85" android:autoMirrored="true"
android:height="24dp" android:tint="#3B76EC"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#ffffffff" android:pathData="M16.59,8.59L12,13.17 7.41,8.59 6,10l6,6 6,-6z"/>
</vector>
//svg_navigate_next:
<vector android:alpha="0.85" android:autoMirrored="true"
android:height="24dp" android:tint="#3B76EC"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#ffffffff" android:pathData="M10,6L8.59,7.41 13.17,12l-4.58,4.59L10,18l6,-6z"/>
</vector>
//---------------------------------------------------------------END----------------------------------------------------------