Android實(shí)現(xiàn)TreeView

實(shí)現(xiàn)的效果圖如下所示:


image.png

1申鱼、定義Node節(jié)點(diǎn)對(duì)象

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

public class Node<T, B> implements Serializable {

    private static final long serialVersionUID = -4492354830247617313L;

    //節(jié)點(diǎn)對(duì)象
    private B Bean;
    //節(jié)點(diǎn)id
    private T id;
    //節(jié)點(diǎn)對(duì)應(yīng)的父級(jí)節(jié)點(diǎn)id,根節(jié)點(diǎn)的id為0
    private T pId;
    //節(jié)點(diǎn)名稱
    private String name;
    //當(dāng)前節(jié)點(diǎn)的級(jí)別
    private int level;
    //是否展開
    private boolean isExpand = false;
    //設(shè)置展開既琴、關(guān)閉的圖片
    private int icon = -1;
    //是否被選中
    private boolean isChecked;
    //子集
    private List<Node> children = new ArrayList<>();
    //父節(jié)點(diǎn)
    private Node parent;
    //節(jié)點(diǎn)文件下載狀態(tài)
    private int status = 0;//0:未下載 1:已下載 2:正在下載

    public Node() {
    }

    public Node(T id, T pId, String name) {
        super();
        this.id = id;
        this.pId = pId;
        this.name = name;
    }

    public B getBean() {
        return Bean;
    }

    public void setBean(B bean) {
        Bean = bean;
    }

    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;
    }

    /**
     * 獲取level
     */
    public int getLevel() {
        return parent == null ? 0 : parent.getLevel() + 1;
    }

    public void setLevel(int level) {
        this.level = level;
    }

    public boolean isExpand() {
        return isExpand;
    }

    /**
     * 設(shè)置展開
     */
    public void setExpand(boolean isExpand) {
        this.isExpand = isExpand;
        if (!isExpand) {
            for (Node node : children) {
                node.setExpand(isExpand);
            }
        }
    }

    public int getIcon() {
        return icon;
    }

    public void setIcon(int icon) {
        this.icon = icon;
    }

    public boolean isChecked() {
        return isChecked;
    }

    public void setChecked(boolean checked) {
        isChecked = checked;
    }

    public List<Node> getChildren() {
        return children;
    }

    public void setChildren(List<Node> children) {
        this.children = children;
    }

    public Node getParent() {
        return parent;
    }

    public void setParent(Node parent) {
        this.parent = parent;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    /**
     * 是否為跟節(jié)點(diǎn)
     */
    public boolean isRoot() {
        return parent == null;
    }

    /**
     * 判斷父節(jié)點(diǎn)是否展開
     */
    public boolean isParentExpand() {
        if (parent == null)
            return false;
        return parent.isExpand();
    }

    /**
     * 是否是葉子節(jié)點(diǎn)
     */
    public boolean isLeaf() {
        return children.size() == 0;
    }

}

2朝扼、定義TreeHelper

import android.text.TextUtils;

import com.glendale.bim.base.R;

import java.util.ArrayList;
import java.util.List;


/**
 * @user:CJJ-SAL
 * @time:2019/8/22 15:38
 * @desc:
 */
public class TreeHelper {

    /**
     * 返回排序后的節(jié)點(diǎn)樹
     */
    public static List<Node> getSortedNodes(List<Node> datas, int defaultExpandLevel) {
        List<Node> result = new ArrayList<Node>();
        // 設(shè)置Node間父子關(guān)系
        List<Node> nodes = convetData2Node(datas);
        // 拿到根節(jié)點(diǎn)
        List<Node> rootNodes = getRootNodes(nodes);
        // 排序以及設(shè)置Node間關(guān)系
        for (Node node : rootNodes) {
            addNode(result, node, defaultExpandLevel, 1);
        }
        return result;
    }

    /**
     * 將我們的數(shù)據(jù)轉(zhuǎn)化為樹的節(jié)點(diǎn)
     */
    public static List<Node> convetData2Node(List<Node> datas) {
        for (int i = 0; i < datas.size(); i++) {
            Node n = datas.get(i);
            for (int j = i + 1; j < datas.size(); j++) {
                Node m = datas.get(j);
                if (m.getpId() instanceof String) {
                    String mId = (String) m.getId();
                    String mpId = (String) m.getpId();
                    String nId = (String) n.getId();
                    String npId = (String) n.getpId();

                    if (TextUtils.equals(mpId, nId)) {
                        n.getChildren().add(m);
                        m.setParent(n);
                    } else if (TextUtils.equals(mId, npId)) {
                        m.getChildren().add(n);
                        n.setParent(m);
                    }
                } else if (m.getpId() instanceof Integer) {
                    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 datas;
    }

    /**
     * 獲取根節(jié)點(diǎn)
     */
    public static List<Node> getRootNodes(List<Node> datas) {
        List<Node> root = new ArrayList<Node>();
        for (Node node : datas) {
            if (node.isRoot())
                root.add(node);
        }
        return root;
    }

    /**
     * 通過(guò)遞歸的方式也拜,把一個(gè)節(jié)點(diǎn)上的所有的子節(jié)點(diǎn)等都按順序放入
     */
    public static <T, B> void addNode(List<Node> nodes, Node<T, B> 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);
        }
    }

    /**
     * 過(guò)濾出所有可見(jiàn)的Node
     */
    public static List<Node> filterVisibleNode(List<Node> nodes) {
        List<Node> result = new ArrayList<Node>();
        for (Node node : nodes) {
            // 如果為跟節(jié)點(diǎn)以舒,或者上層目錄為展開狀態(tài)
            if (node.isRoot() || node.isParentExpand()) {
                setNodeIcon(node);
                result.add(node);
            }
        }
        return result;
    }

    /**
     * 設(shè)置節(jié)點(diǎn)的圖標(biāo)
     */
    private static void setNodeIcon(Node node) {
        if (node.getChildren().size() > 0 && node.isExpand()) {
            node.setIcon(R.drawable.icon_node_expanding);
        } else if (node.getChildren().size() > 0 && !node.isExpand()) {
            node.setIcon(R.drawable.icon_node_no_expanding);
        } else {
            node.setIcon(-1);
        }
    }
}

3、實(shí)現(xiàn)ListView適配器

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListView;

import java.util.ArrayList;
import java.util.List;

/**
 * @user:CJJ-SAL
 * @time:2019/8/22 15:14
 * @desc:
 */
public abstract class TreeListViewAdapter extends BaseAdapter {

    protected Context context;
    protected LayoutInflater mInflater;
    //存儲(chǔ)所有可見(jiàn)的Node
    protected List<Node> mNodes = new ArrayList<>();
    //存儲(chǔ)所有的Node
    protected List<Node> mAllNodes = new ArrayList<>();
    //節(jié)點(diǎn)點(diǎn)擊接口
    private OnTreeNodeClickListener onTreeNodeClickListener;
    private OnTreeNodeLongClickListener onTreeNodeLongClickListener;
    //默認(rèn)不展開
    private int defaultExpandLevel = 0;
    //展開與關(guān)閉的圖片
    private int iconExpand = -1, iconNoExpand = -1;

    private List<Node> mDatas = new ArrayList<>();
    private ListView mTree;

    public TreeListViewAdapter(ListView mTree, Context context, List<Node> mDatas, int defaultExpandLevel) {
        this.mTree = mTree;
        this.context = context;
        this.mDatas = mDatas;
        this.defaultExpandLevel = defaultExpandLevel;
        initData();
    }

    public void initData() {
        if (null == mDatas || mDatas.size() == 0) {
            return;
        }
        mInflater = LayoutInflater.from(context);
        //對(duì)所有的Node進(jìn)行排序
        mAllNodes = TreeHelper.getSortedNodes(mDatas, defaultExpandLevel);
        //過(guò)濾出可見(jiàn)的Node
        mNodes = TreeHelper.filterVisibleNode(mAllNodes);
        mTree.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                expandOrCollapse(position);
                if (onTreeNodeClickListener != null) {
                    onTreeNodeClickListener.onClick(mNodes.get(position), position);
                }
            }
        });
        mTree.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                if (onTreeNodeLongClickListener != null) {
                    onTreeNodeLongClickListener.onLongClick(mNodes.get(position), position);
                }
                return true;
            }
        });
    }

    @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);
        // 設(shè)置內(nèi)邊距
        convertView.setPadding(node.getLevel() * 20, 3, 3, 3);
        return convertView;
    }

    /**
     * 相應(yīng)ListView的點(diǎn)擊事件 展開或關(guān)閉某節(jié)點(diǎn)
     */
    public void expandOrCollapse(int position) {
        Node n = mNodes.get(position);
        if (n != null) {// 排除傳入?yún)?shù)錯(cuò)誤異常
            if (!n.isLeaf()) {
                n.setExpand(!n.isExpand());
                mNodes = TreeHelper.filterVisibleNode(mAllNodes);
                notifyDataSetChanged();// 刷新視圖
            }
        }
    }

    /**
     * 設(shè)置節(jié)點(diǎn)選中狀態(tài)
     *
     * @param node
     * @param isChecked
     */
    public void setChecked(Node node, boolean isChecked) {
        node.setChecked(isChecked);
        setChildChecked(node, isChecked);
        if (node.getParent() != null) {
            setNodeParentChecked(node.getParent(), isChecked);
        }
        notifyDataSetChanged();
    }

    /**
     * 獲取排序后所有節(jié)點(diǎn)
     *
     * @return
     */
    public List<Node> getAllNodes() {
        if (mAllNodes == null)
            mAllNodes = new ArrayList<Node>();
        return mAllNodes;
    }

    /**
     * 設(shè)置子節(jié)點(diǎn)的選中狀態(tài)
     *
     * @param node
     * @param isChecked
     * @param <T>
     * @param <B>
     */
    public <T, B> void setChildChecked(Node<T, B> node, boolean isChecked) {
        if (!node.isLeaf()) {
            node.setChecked(isChecked);
            for (Node childrenNode : node.getChildren()) {
                setChildChecked(childrenNode, isChecked);
            }
        } else {
            node.setChecked(isChecked);
        }
    }

    /**
     * 設(shè)置節(jié)點(diǎn)的父級(jí)選中狀態(tài)
     *
     * @param node
     * @param checked
     */
    private void setNodeParentChecked(Node node, boolean checked) {
        if (checked) {
            node.setChecked(checked);
            if (node.getParent() != null) {
                setNodeParentChecked(node.getParent(), checked);
            }
        } else {
            List<Node> childrens = node.getChildren();
            boolean isChecked = false;
            for (Node children : childrens) {
                if (children.isChecked()) {
                    isChecked = true;
                }
            }
            //如果所有子節(jié)點(diǎn)都沒(méi)有被選中 父節(jié)點(diǎn)也不選中
            if (!isChecked) {
                node.setChecked(checked);
            }
            if (node.getParent() != null) {
                setNodeParentChecked(node.getParent(), checked);
            }
        }
    }

    public void setOnTreeNodeClickListener(OnTreeNodeClickListener onTreeNodeClickListener) {
        this.onTreeNodeClickListener = onTreeNodeClickListener;
    }

    public void setOnTreeNodeLongClickListener(OnTreeNodeLongClickListener onTreeNodeLongClickListener) {
        this.onTreeNodeLongClickListener = onTreeNodeLongClickListener;
    }

    public abstract View getConvertView(Node node, int position, View convertView, ViewGroup parent);

}

4慢哈、實(shí)現(xiàn)TreeRecyclerAdapter適配器

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;

import java.util.ArrayList;
import java.util.List;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

/**
 * @user:CJJ-SAL
 * @time:2019/11/21 11:48
 * @desc:
 */
public abstract class TreeRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    protected Context context;
    protected LayoutInflater mInflater;
    //存儲(chǔ)所有可見(jiàn)的Node
    protected List<Node> mNodes = new ArrayList<>();
    //存儲(chǔ)所有的Node
    protected List<Node> mAllNodes = new ArrayList<>();
    //節(jié)點(diǎn)點(diǎn)擊接口
    private OnTreeNodeClickListener onTreeNodeClickListener;
    private OnTreeNodeLongClickListener onTreeNodeLongClickListener;
    //默認(rèn)不展開
    private int defaultExpandLevel = 0;
    //展開與關(guān)閉的圖片
    private int iconExpand = -1, iconNoExpand = -1;

    private List<Node> mDatas = new ArrayList<>();
    private RecyclerView mTree;

    public TreeRecyclerAdapter(RecyclerView mTree, Context context, List<Node> datas, int defaultExpandLevel) {
        setHasStableIds(true);
        this.mTree = mTree;
        this.context = context;
        this.mDatas = datas;
        this.defaultExpandLevel = defaultExpandLevel;
        initData();
    }

    public void initData() {
        if (null == mDatas || mDatas.size() == 0) {
            return;
        }
        mInflater = LayoutInflater.from(context);
        //對(duì)所有的Node進(jìn)行排序
        mAllNodes = TreeHelper.getSortedNodes(mDatas, defaultExpandLevel);
        //過(guò)濾出可見(jiàn)的Node
        mNodes = TreeHelper.filterVisibleNode(mAllNodes);
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {


        Node node = mNodes.get(position);
        // 設(shè)置內(nèi)邊距
        holder.itemView.setPadding(node.getLevel() * 20, 3, 3, 3);
        //設(shè)置點(diǎn)擊事件
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                expandOrCollapse(position);
                if (onTreeNodeClickListener != null) {
                    onTreeNodeClickListener.onClick(mNodes.get(position), position);
                }
            }
        });
        //設(shè)置長(zhǎng)按點(diǎn)擊事件
        holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                if (onTreeNodeLongClickListener != null) {
                    onTreeNodeLongClickListener.onLongClick(mNodes.get(position), position);
                }
                return true;
            }
        });
        onBindViewHolder(node, holder, position);
    }

    @Override
    public int getItemCount() {
        return mNodes.size();
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    /**
     * 相應(yīng)ListView的點(diǎn)擊事件 展開或關(guān)閉某節(jié)點(diǎn)
     */
    public void expandOrCollapse(int position) {
        Node n = mNodes.get(position);
        if (n != null) {// 排除傳入?yún)?shù)錯(cuò)誤異常
            if (!n.isLeaf()) {
                n.setExpand(!n.isExpand());
                mNodes = TreeHelper.filterVisibleNode(mAllNodes);
                notifyDataSetChanged();// 刷新視圖
            }
        }
    }

    /**
     * 獲取排序后所有節(jié)點(diǎn)
     *
     * @return
     */
    public List<Node> getAllNodes() {
        if (mAllNodes == null)
            mAllNodes = new ArrayList<Node>();
        return mAllNodes;
    }

    /**
     * 設(shè)置節(jié)點(diǎn)選中狀態(tài)
     *
     * @param node
     * @param isChecked
     */
    public void setChecked(Node node, boolean isChecked) {
        node.setChecked(isChecked);
        setChildChecked(node, isChecked);
        if (node.getParent() != null) {
            setNodeParentChecked(node.getParent(), isChecked);
        }
        notifyDataSetChanged();
    }

    /**
     * 設(shè)置子節(jié)點(diǎn)的選中狀態(tài)
     *
     * @param node
     * @param isChecked
     * @param <T>
     * @param <B>
     */
    public <T, B> void setChildChecked(Node<T, B> node, boolean isChecked) {
        if (!node.isLeaf()) {
            node.setChecked(isChecked);
            for (Node childrenNode : node.getChildren()) {
                setChildChecked(childrenNode, isChecked);
            }
        } else {
            node.setChecked(isChecked);
        }
    }

    /**
     * 設(shè)置節(jié)點(diǎn)的父級(jí)選中狀態(tài)
     *
     * @param node
     * @param checked
     */
    private void setNodeParentChecked(Node node, boolean checked) {
        if (checked) {
            node.setChecked(checked);
            if (node.getParent() != null) {
                setNodeParentChecked(node.getParent(), checked);
            }
        } else {
            List<Node> childrens = node.getChildren();
            boolean isChecked = false;
            for (Node children : childrens) {
                if (children.isChecked()) {
                    isChecked = true;
                }
            }
            //如果所有子節(jié)點(diǎn)都沒(méi)有被選中 父節(jié)點(diǎn)也不選中
            if (!isChecked) {
                node.setChecked(checked);
            }
            if (node.getParent() != null) {
                setNodeParentChecked(node.getParent(), checked);
            }
        }
    }

    public void setOnTreeNodeClickListener(OnTreeNodeClickListener onTreeNodeClickListener) {
        this.onTreeNodeClickListener = onTreeNodeClickListener;
    }

    public void setOnTreeNodeLongClickListener(OnTreeNodeLongClickListener onTreeNodeLongClickListener) {
        this.onTreeNodeLongClickListener = onTreeNodeLongClickListener;
    }

    public abstract void onBindViewHolder(Node node, RecyclerView.ViewHolder holder, final int position);
}

5蔓钟、定義節(jié)點(diǎn)的點(diǎn)擊事件

/**
 * @user:CJJ-SAL
 * @time:2019/8/22 15:20
 * @desc:節(jié)點(diǎn)點(diǎn)擊事件
 */
public interface OnTreeNodeClickListener {
    void onClick(Node node, int position);
}

/**
 * @user:CJJ-SAL
 * @time:2019/8/22 15:20
 * @desc:節(jié)點(diǎn)長(zhǎng)按事件
 */
public interface OnTreeNodeLongClickListener {
    void onLongClick(Node node, int position);
}

6、可以使用下面的測(cè)試數(shù)據(jù)進(jìn)行測(cè)試
測(cè)試數(shù)據(jù)如下:

[
 {
   "parentTaskId": "0",
   "taskId": "1",
   "taskName": "福建移動(dòng)廈門數(shù)據(jù)中心",
   "taskType": 1,
   "taskFormType": 0
 },
 {
   "parentTaskId": "1",
   "taskId": "2",
   "taskName": "一層",
   "taskType": 2,
   "taskFormType": 0
 },
 {
   "parentTaskId": "2",
   "taskId": "3",
   "taskName": " 樁基",
   "taskType": 3,
   "taskFormType": 1
 },
 {
   "parentTaskId": "2",
   "taskId": "4",
   "taskName": "承臺(tái)系梁",
   "taskType": 3,
   "taskFormType": 2
 },
 {
   "parentTaskId": "2",
   "taskId": "5",
   "taskName": "墩柱",
   "taskType": 3,
   "taskFormType": 3
 },
 {
   "parentTaskId": "2",
   "taskId": "6",
   "taskName": "蓋梁",
   "taskType": 3,
   "taskFormType": 4
 },
 {
   "parentTaskId": "2",
   "taskId": "7",
   "taskName": "箱梁",
   "taskType": 3,
   "taskFormType": 5
 }
]
public class TestDemoAdapter extends TreeRecyclerAdapter {

    public TestDemoAdapter (RecyclerView mTree, Context context, List<Node> datas, int defaultExpandLevel) {
        super(mTree, context, datas, defaultExpandLevel);
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        GlTreeViewItemBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.gl_tree_view_item, parent, false);
        MyViewHolder holder = new MyViewHolder(binding.getRoot());
        holder.setBinding(binding);
        return holder;
    }

    @Override
    public void onBindViewHolder(Node node, RecyclerView.ViewHolder holder, int position) {
        MyViewHolder myViewHolder = (MyViewHolder) holder;
        myViewHolder.setData(node, position);
    }

    class MyViewHolder extends RecyclerView.ViewHolder {

        GlTreeViewItemBinding binding;

        public GlTreeViewItemBinding getBinding() {
            return binding;
        }

        public void setBinding(GlTreeViewItemBinding binding) {
            this.binding = binding;
        }

        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
        }

        public void setData(Node node, int position) {
            //設(shè)置展開關(guān)閉的icon
            if (node.getIcon() == -1) {
                binding.imgTreeIcon.setVisibility(View.INVISIBLE);
            } else {
                binding.imgTreeIcon.setVisibility(View.VISIBLE);
                binding.imgTreeIcon.setImageResource(node.getIcon());
            }
            //設(shè)置父節(jié)點(diǎn)是否顯示選擇的控件
            binding.imgTreeChoose.setVisibility(View.GONE);
//            if (node.getChildren().size() > 0) {
//                binding.imgTreeChoose.setVisibility(View.GONE);
//            } else {
//                binding.imgTreeChoose.setVisibility(View.VISIBLE);
//            }
            //設(shè)置選中狀態(tài)的icon
//            if (node.isChecked()) {//選中
//                node.setChecked(true);
//                binding.imgTreeChoose.setImageResource(R.drawable.ic_checkbox_checked);
//            } else {//未選中
//                node.setChecked(false);
//                binding.imgTreeChoose.setImageResource(R.drawable.ic_checkbox_uncheck);
//            }

//            binding.imgTreeChoose.setOnClickListener(new View.OnClickListener() {
//                @Override
//                public void onClick(View v) {
//                    boolean isChecked = node.isChecked();
//                    isChecked = !isChecked;
//                    LogUtil.E("是否選中:" + isChecked);
//                    node.setChecked(isChecked);
//                    //設(shè)置選中的狀態(tài)
//                    //setChecked(node, isChecked);
//                    if (isChecked) {
//                        binding.imgTreeChoose.setImageResource(R.drawable.ic_checkbox_checked);
//                    } else {
//                        binding.imgTreeChoose.setImageResource(R.drawable.ic_checkbox_uncheck);
//                    }
//                    //節(jié)點(diǎn)選擇結(jié)果回調(diào)接口
//                    if (null != onItemCheckedListener) {
//                        onItemCheckedListener.onSelectedNodes(node, position);
//                    }
//                }
//            });
            binding.textNodeName.setText(node.getName());
        }
    }

    //節(jié)點(diǎn)選擇回調(diào)接口
    public interface OnItemCheckedListener {
        void onSelectedNodes(Node node, int position);
    }

    private OnItemCheckedListener onItemCheckedListener;

    public void setOnItemCheckedListener(OnItemCheckedListener onItemCheckedListener) {
        this.onItemCheckedListener = onItemCheckedListener;
    }
}

創(chuàng)建布局gl_tree_view_item

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:background="@drawable/bg_list_item_"
        android:gravity="center_vertical"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/imgTreeIcon"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:padding="5dp"
            tools:ignore="ContentDescription" />

        <ImageView
            android:id="@+id/imgTreeChoose"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:padding="5dp"
            tools:ignore="ContentDescription" />

        <TextView
            android:id="@+id/textNodeName"
            android:layout_width="0dp"
            android:layout_height="30dp"
            android:layout_weight="1"
            android:ellipsize="end"
            android:gravity="center|left"
            android:singleLine="true"
            android:textColor="#333333"
            android:textSize="15sp" />

    </LinearLayout>
</layout>

View層代碼自己實(shí)現(xiàn)哦

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末岸军,一起剝皮案震驚了整個(gè)濱河市奋刽,隨后出現(xiàn)的幾起案子瓦侮,更是在濱河造成了極大的恐慌,老刑警劉巖佣谐,帶你破解...
    沈念sama閱讀 216,744評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肚吏,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡狭魂,警方通過(guò)查閱死者的電腦和手機(jī)罚攀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)雌澄,“玉大人斋泄,你說(shuō)我怎么就攤上這事「湮” “怎么了炫掐?”我有些...
    開封第一講書人閱讀 163,105評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)睬涧。 經(jīng)常有香客問(wèn)我募胃,道長(zhǎng),這世上最難降的妖魔是什么畦浓? 我笑而不...
    開封第一講書人閱讀 58,242評(píng)論 1 292
  • 正文 為了忘掉前任痹束,我火速辦了婚禮,結(jié)果婚禮上讶请,老公的妹妹穿的比我還像新娘祷嘶。我一直安慰自己,他們只是感情好夺溢,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,269評(píng)論 6 389
  • 文/花漫 我一把揭開白布论巍。 她就那樣靜靜地躺著,像睡著了一般风响。 火紅的嫁衣襯著肌膚如雪环壤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,215評(píng)論 1 299
  • 那天钞诡,我揣著相機(jī)與錄音,去河邊找鬼湃崩。 笑死荧降,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的攒读。 我是一名探鬼主播朵诫,決...
    沈念sama閱讀 40,096評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼薄扁!你這毒婦竟也來(lái)了剪返?” 一聲冷哼從身側(cè)響起废累,我...
    開封第一講書人閱讀 38,939評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎脱盲,沒(méi)想到半個(gè)月后邑滨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,354評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡钱反,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,573評(píng)論 2 333
  • 正文 我和宋清朗相戀三年掖看,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片面哥。...
    茶點(diǎn)故事閱讀 39,745評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡哎壳,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出尚卫,到底是詐尸還是另有隱情归榕,我是刑警寧澤,帶...
    沈念sama閱讀 35,448評(píng)論 5 344
  • 正文 年R本政府宣布吱涉,位于F島的核電站刹泄,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏邑飒。R本人自食惡果不足惜循签,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,048評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望疙咸。 院中可真熱鬧县匠,春花似錦、人聲如沸撒轮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)题山。三九已至兰粉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間顶瞳,已是汗流浹背玖姑。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留慨菱,地道東北人焰络。 一個(gè)月前我還...
    沈念sama閱讀 47,776評(píng)論 2 369
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像符喝,于是被迫代替她去往敵國(guó)和親闪彼。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,652評(píng)論 2 354