精华内容
下载资源
问答
  • 关于Android移动端多级列表(超过两)的几种实现方式,包含静态(展示前已能获取全部数据)和动态(子数据需点击父数据后获取)两种形式

    通常这种多级列表更多见于web端,移动端常见为省份选择之类的情况(类似QQ分组的通常只有两级),由于手机屏幕的限制,相当一部分也选择多个页面显示,所以也许用得不是很多,但俗话说,只有想不到的需求,没有不被要求到的需求,所以吐舌头以防万一吧……

    首先,最常见的为类似于省市这种形式的列表,特征是在展示前你可以获得全部数据,包括子列表,这也是最常见的多级列表形式。谷歌官方有提供ExpandableListView,可以实现两级列表,我个人以为,也这表明谷歌本身也只推荐手机端只实现两级的缩进(纯吐槽:坦白说以手机屏幕的宽度来看,在同一页面通过缩进来显示两级以上多级的层级关系真是毫无美感可言)。多级列表网上有一些实现方式,主要是前两种,都是展示前可以获得全部数据的,第三种是动态获取子列表数据时的实现方式,如下:


    第一种方式:以单个listView实现,纯粹依赖缩进来造成层级效果

    这种实现方式实质是以一个ListView列表来实现,无论是子列表数据还是父列表数据,展示时实际是处于同一级的,只是通过给子数据添加缩进,人为的制造出层级关系,看起来像是多级列表而已。取根列表数据资源存于代码中的firstLayerList列表,全部列表数据资源于totalList列表,但列表中每一项并不是直接的数据资源,而是数据本身、层级、数据本身id、数据父id、是否有子数据、是否已展开的一个封装对象。如:列表为List<Data>,数据为Data(String dataStr,int layer,long dataId,long dataParentId,boolean hasSubDatas,boolean isExpand);

    在getView()方法中注意两点,一是根据子列表的层级计算并添加缩进,二是注意可见性,因为在convertView复用过程中有可能会复用可见性与当前项不同的view。

    然后就是OnItemClickListener()方法,分三种情况:

    • 若是点击项无子数据,点击不响应,return。
    • 若是点击项有子数据并已展开,则响应为隐藏子数据,具体实现方式为从当前项下一项开始,以当前列表总项数为上限循环,对当前项之后的每一项作层级判断,如果layer值大于当前点击的position项的layer值,则说明为当前项的子数据、子子数据、子子子数据等,一直遍历到某一项layer值小于或等于当前选中position项的layerw值时break出循环,将遍历到的这些数据存入toDelList列表,然后通过removeAll(...)从当前列表的数据列表firstLayerList中移除toDelList列表中的所有数据项,调用notifyDataSetChanged()方法刷新列表。
    • 若是点击项有子数据但未展开,则响应为展示子数据,具体实现方式为取当前点击项的dataId,遍历全部数据列表totalList,取每一项的dataParentId与当前点击项dataId比较,如果相等则说明为需要展示的子数据(当然,只是下一级子节点,好在需求也只是下一级),分别存入当前展示数据列表中的第position + i项,i从1开始累加,遍历完totalList列表后,刷新列表,会显示为展开子列表。
    第二种方式:通过修改ExpandableListView来实现

    这种方式虽可实现,但比较繁复,且ExpandableListView本身提供的一些方法又不能直接用了,不推荐。


    第三种,动态获取数据实现三级列表

    这种针对的是在展示之前无法获取到子数据的情况,就是必须点击父数据项才去请求子数据的情况。

    在我的示例里,拿到的作务列表中该任务数据中是包含有子任务数的,即下例中的getSubs()方法得到的b子任务数。

    公司项目,只能截取代码片段了,adapter,subAdapter,grandSubAdapter是同一类的不同对象实现。
        /**
         * 任务列表监听
         */
        private AdapterView.OnItemClickListener taskItemListener = new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                if (0 != ((Task) (mAdapter.getItem((int) id))).getSubs()) {//在没有表头的前提下,(int)id和position是一样的效果,只是个人习惯
                    subListView = (ListView) view.findViewById(R.id.sub_task_list);//在adapter的xml布局里,最下方包含一个<ListView ...../>,默认为隐藏状态View.GONE
                    //subListView.setAdapter(subAdapter);
                    if (View.VISIBLE == subListView.getVisibility()) {//当子listView可见时,说明是展开状态,点击时的响应就应该是关闭
                        subListView.setVisibility(View.GONE);
                    } else {//子listView不可见,则展开子列表
                        subListView.setVisibility(View.VISIBLE);
                        subListView.setFocusable(false);
                        subListView.setOnItemClickListener(subTaskItemListener);
                        
                requestSubListDatas(((Task)(mAdapter.getItem((int)id))).getId());//参数为当前任务项id,请求该任务的子任务数据
        //这里我是以Message形式传递给handler处理,为了便于阅读,就放在这里吧
       subAdapter.setmTasks(子任务列表数据);
       
       ViewGroup.LayoutParams parentLp = subListView.getLayoutParams();
       //这里可添加判断,只需计算一次即可
      measureView = subAdapter.getView(0,null,subListView);//measureView为一个View对象
      //注意在这里要求Adapter的布局文件中的listView控件的父容器为LinearLayout布局,否则会报错
      measureView.measure(0,0);
      parentLp.height = measureView.getMeasuredHeight() * subAdapter.getCount();
    subListView.setLayoutParams(parentLp);

    subListView.setAdapter(subAdapter);
                    }
                }
            }
        };


        /**
         * 子任务列表监听
         */
        private AdapterView.OnItemClickListener subTaskItemListener = new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View subView, int position, long subId) {
                if (0 != ((Task) (subAdapter.getItem((int) subId))).getSubs()) {
                    grandSubListView = (ListView) subView.findViewById(R.id.sub_task_list);
                    //grandSubListView.setAdapter(grandSubAdapter);
                    if (View.VISIBLE == grandSubListView.getVisibility()) {
                        grandSubListView.setVisibility(View.GONE);
                        //grandSubListView.setLayoutParams(subParentParams);
                        ViewGroup.LayoutParams mParentParams = subListView.getLayoutParams();
                        mParentParams.height -= grandSubListView.getLayoutParams().height;
                        subListView.setLayoutParams(mParentParams);
                    } else {
                        grandSubListView.setVisibility(View.VISIBLE);
                        grandSubListView.setFocusable(false);

                        //与以上任务列表监听相似,就不重复了

                    }
                }
            }
        };

    实现起来也不难,最主要是需在子列表展开前计算出子列表的高度以提供给子列表展示的空间。

    展开全文
  • android多级列表

    千次阅读 2016-11-16 11:33:51
    我们开发app过程中,经常会碰到需要 多级列表展示的效果。而android原生sdk中根本没有3级 4级甚至更多级别的列表控件。 ...android中有ExpandListView控件,但是这个控件支持两级列表。对于多
    
    

    我们开发app过程中,经常会碰到需要 多级列表展示的效果。而android原生sdk中根本没有3级 4级甚至更多级别的列表控件。

    所以我们就要自己去实现一个类似treeListView 的控件,下面这个是我项目中的一个效果图,可支持多级列表扩展。


               


    android中有ExpandListView控件,但是这个控件只支持两级列表。对于多级列表如果重写这个不是很好用。

    实现这种列表 思想就是递归,构造一个子父级的关系。

    话不多说 代码中体会

    Activity


    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. package com.example.customtreeviewdemo;  
    2.   
    3. import java.util.ArrayList;  
    4. import java.util.List;  
    5.   
    6. import android.app.Activity;  
    7. import android.os.Bundle;  
    8. import android.view.View;  
    9. import android.view.View.OnClickListener;  
    10. import android.widget.Button;  
    11. import android.widget.ListView;  
    12. import android.widget.Toast;  
    13.   
    14. import com.example.customtreeviewdemo.bean.MyNodeBean;  
    15. import com.example.customtreeviewdemo.tree.Node;  
    16. import com.example.customtreeviewdemo.tree.TreeListViewAdapter.OnTreeNodeClickListener;  
    17.   
    18. public class MainActivity extends Activity {  
    19.   
    20.     private ListView treeLv;  
    21.     private Button checkSwitchBtn;  
    22.     private MyTreeListViewAdapter<MyNodeBean> adapter;  
    23.     private List<MyNodeBean> mDatas = new ArrayList<MyNodeBean>();  
    24.     //标记是显示Checkbox还是隐藏  
    25.     private boolean isHide = true;  
    26.   
    27.     @Override  
    28.     protected void onCreate(Bundle savedInstanceState) {  
    29.         super.onCreate(savedInstanceState);  
    30.         setContentView(R.layout.activity_main);  
    31.   
    32.         initDatas();  
    33.         treeLv = (ListView) this.findViewById(R.id.tree_lv);  
    34.         checkSwitchBtn = (Button)this.findViewById(R.id.check_switch_btn);  
    35.           
    36.         checkSwitchBtn.setOnClickListener(new OnClickListener(){  
    37.   
    38.             @Override  
    39.             public void onClick(View v) {  
    40.                 if(isHide){  
    41.                     isHide = false;  
    42.                 }else{  
    43.                     isHide = true;  
    44.                 }  
    45.                   
    46.                 adapter.updateView(isHide);  
    47.             }  
    48.               
    49.         });  
    50.         try {  
    51.             adapter = new MyTreeListViewAdapter<MyNodeBean>(treeLv, this,  
    52.                     mDatas, 10, isHide);  
    53.   
    54.             adapter.setOnTreeNodeClickListener(new OnTreeNodeClickListener() {  
    55.                 @Override  
    56.                 public void onClick(Node node, int position) {  
    57.                     if (node.isLeaf()) {  
    58.                         Toast.makeText(getApplicationContext(), node.getName(),  
    59.                                 Toast.LENGTH_SHORT).show();  
    60.                     }  
    61.                 }  
    62.   
    63.                 @Override  
    64.                 public void onCheckChange(Node node, int position,  
    65.                         List<Node> checkedNodes) {  
    66.   
    67.                     StringBuffer sb = new StringBuffer();  
    68.                     for (Node n : checkedNodes) {  
    69.                         int pos = n.getId() - 1;  
    70.                         sb.append(mDatas.get(pos).getName()).append("---")  
    71.                                 .append(pos + 1).append(";");  
    72.   
    73.                     }  
    74.   
    75.                     Toast.makeText(getApplicationContext(), sb.toString(),  
    76.                             Toast.LENGTH_SHORT).show();  
    77.                 }  
    78.   
    79.             });  
    80.         } catch (IllegalArgumentException e) {  
    81.             e.printStackTrace();  
    82.         } catch (IllegalAccessException e) {  
    83.             e.printStackTrace();  
    84.         }  
    85.         treeLv.setAdapter(adapter);  
    86.   
    87.     }  
    88.   
    89.     private void initDatas() {  
    90.         mDatas.add(new MyNodeBean(10"中国古代"));  
    91.         mDatas.add(new MyNodeBean(21"唐朝"));  
    92.         mDatas.add(new MyNodeBean(31"宋朝"));  
    93.         mDatas.add(new MyNodeBean(41"明朝"));  
    94.         mDatas.add(new MyNodeBean(52"李世民"));  
    95.         mDatas.add(new MyNodeBean(62"李白"));  
    96.   
    97.         mDatas.add(new MyNodeBean(73"赵匡胤"));  
    98.         mDatas.add(new MyNodeBean(83"苏轼"));  
    99.   
    100.         mDatas.add(new MyNodeBean(94"朱元璋"));  
    101.         mDatas.add(new MyNodeBean(104"唐伯虎"));  
    102.         mDatas.add(new MyNodeBean(114"文征明"));  
    103.         mDatas.add(new MyNodeBean(127"赵建立"));  
    104.         mDatas.add(new MyNodeBean(138"苏东东"));  
    105.         mDatas.add(new MyNodeBean(1410"秋香"));  
    106.     }  
    107. }  


    Adapter

    这个adapter是继承了自己的定义的一个TreeListViewAdapter,核心实现都是在TreeListViewAdapter这个里面


    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. package com.example.customtreeviewdemo;  
    2.   
    3. import java.util.List;  
    4.   
    5. import android.content.Context;  
    6. import android.view.View;  
    7. import android.view.ViewGroup;  
    8. import android.widget.CheckBox;  
    9. import android.widget.CompoundButton;  
    10. import android.widget.CompoundButton.OnCheckedChangeListener;  
    11. import android.widget.ImageView;  
    12. import android.widget.ListView;  
    13. import android.widget.TextView;  
    14.   
    15. import com.example.customtreeviewdemo.tree.Node;  
    16. import com.example.customtreeviewdemo.tree.TreeListViewAdapter;  
    17.   
    18. public class MyTreeListViewAdapter<T> extends TreeListViewAdapter<T> {  
    19.   
    20.     public MyTreeListViewAdapter(ListView mTree, Context context,  
    21.             List<T> datas, int defaultExpandLevel,boolean isHide)  
    22.             throws IllegalArgumentException, IllegalAccessException {  
    23.         super(mTree, context, datas, defaultExpandLevel,isHide);  
    24.     }  
    25.       
    26.     @SuppressWarnings("unchecked")  
    27.     @Override  
    28.     public View getConvertView(Node node, int position, View convertView,  
    29.             ViewGroup parent) {  
    30.         ViewHolder viewHolder = null;  
    31.         if (convertView == null)  
    32.         {  
    33.             convertView = mInflater.inflate(R.layout.list_item, parent, false);  
    34.             viewHolder = new ViewHolder();  
    35.             viewHolder.icon = (ImageView) convertView  
    36.                     .findViewById(R.id.id_treenode_icon);  
    37.             viewHolder.label = (TextView) convertView  
    38.                     .findViewById(R.id.id_treenode_name);  
    39.             viewHolder.checkBox = (CheckBox)convertView.findViewById(R.id.id_treeNode_check);  
    40.               
    41.             convertView.setTag(viewHolder);  
    42.   
    43.         } else  
    44.         {  
    45.             viewHolder = (ViewHolder) convertView.getTag();  
    46.         }  
    47.   
    48.         if (node.getIcon() == -1)  
    49.         {  
    50.             viewHolder.icon.setVisibility(View.INVISIBLE);  
    51.         } else  
    52.         {  
    53.             viewHolder.icon.setVisibility(View.VISIBLE);  
    54.             viewHolder.icon.setImageResource(node.getIcon());  
    55.         }  
    56.   
    57.         if(node.isHideChecked()){  
    58.             viewHolder.checkBox.setVisibility(View.GONE);  
    59.         }else{  
    60.             viewHolder.checkBox.setVisibility(View.VISIBLE);  
    61.             setCheckBoxBg(viewHolder.checkBox,node.isChecked());  
    62.         }  
    63.         viewHolder.label.setText(node.getName());  
    64.           
    65.           
    66.         return convertView;  
    67.     }  
    68.     private final class ViewHolder  
    69.     {  
    70.         ImageView icon;  
    71.         TextView label;  
    72.         CheckBox checkBox;  
    73.     }  
    74.       
    75.     /** 
    76.      * checkbox是否显示 
    77.      * @param cb 
    78.      * @param isChecked 
    79.      */  
    80.     private void setCheckBoxBg(CheckBox cb,boolean isChecked){  
    81.         if(isChecked){  
    82.             cb.setBackgroundResource(R.drawable.check_box_bg_check);  
    83.         }else{  
    84.             cb.setBackgroundResource(R.drawable.check_box_bg);  
    85.         }  
    86.     }  
    87. }  


    自定义TreeListViewAdapter  这个是整个树形结构的一个适配器,这里面主要是实现对Node节点的操作 点击,选中改变 更新等


    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. package com.example.customtreeviewdemo.tree;  
    2.   
    3. import java.util.ArrayList;  
    4. import java.util.List;  
    5.   
    6. import android.content.Context;  
    7. import android.view.LayoutInflater;  
    8. import android.view.View;  
    9. import android.view.ViewGroup;  
    10. import android.widget.AdapterView;  
    11. import android.widget.AdapterView.OnItemClickListener;  
    12. import android.widget.BaseAdapter;  
    13. import android.widget.CheckBox;  
    14. import android.widget.CompoundButton;  
    15. import android.widget.CompoundButton.OnCheckedChangeListener;  
    16. import android.widget.ListView;  
    17. import android.widget.RelativeLayout;  
    18.   
    19. /** 
    20.  * tree适配器 
    21.  * @param <T> 
    22.  */  
    23. public abstract class TreeListViewAdapter<T> extends BaseAdapter {  
    24.   
    25.     protected Context mContext;  
    26.     /** 
    27.      * 存储所有可见的Node 
    28.      */  
    29.     protected List<Node> mNodes;  
    30.     protected LayoutInflater mInflater;  
    31.     /** 
    32.      * 存储所有的Node 
    33.      */  
    34.     protected List<Node> mAllNodes;  
    35.   
    36.     /** 
    37.      * 点击的回调接口 
    38.      */  
    39.     private OnTreeNodeClickListener onTreeNodeClickListener;  
    40.   
    41.     public interface OnTreeNodeClickListener {  
    42.         /** 
    43.          * 处理node click事件 
    44.          * @param node 
    45.          * @param position 
    46.          */  
    47.         void onClick(Node node, int position);  
    48.         /** 
    49.          * 处理checkbox选择改变事件 
    50.          * @param node 
    51.          * @param position 
    52.          * @param checkedNodes 
    53.          */  
    54.         void onCheckChange(Node node, int position,List<Node> checkedNodes);  
    55.     }  
    56.   
    57.     public void setOnTreeNodeClickListener(  
    58.             OnTreeNodeClickListener onTreeNodeClickListener) {  
    59.         this.onTreeNodeClickListener = onTreeNodeClickListener;  
    60.     }  
    61.   
    62.     /** 
    63.      *  
    64.      * @param mTree 
    65.      * @param context 
    66.      * @param datas 
    67.      * @param defaultExpandLevel 
    68.      *            默认展开几级树 
    69.      * @throws IllegalArgumentException 
    70.      * @throws IllegalAccessException 
    71.      */  
    72.     public TreeListViewAdapter(ListView mTree, Context context, List<T> datas,  
    73.             int defaultExpandLevel, boolean isHide)  
    74.             throws IllegalArgumentException, IllegalAccessException {  
    75.         mContext = context;  
    76.         /** 
    77.          * 对所有的Node进行排序 
    78.          */  
    79.         mAllNodes = TreeHelper  
    80.                 .getSortedNodes(datas, defaultExpandLevel, isHide);  
    81.         /** 
    82.          * 过滤出可见的Node 
    83.          */  
    84.         mNodes = TreeHelper.filterVisibleNode(mAllNodes);  
    85.         mInflater = LayoutInflater.from(context);  
    86.   
    87.         /** 
    88.          * 设置节点点击时,可以展开以及关闭;并且将ItemClick事件继续往外公布 
    89.          */  
    90.         mTree.setOnItemClickListener(new OnItemClickListener() {  
    91.             @Override  
    92.             public void onItemClick(AdapterView<?> parent, View view,  
    93.                     int position, long id) {  
    94.                 expandOrCollapse(position);  
    95.   
    96.                 if (onTreeNodeClickListener != null) {  
    97.                     onTreeNodeClickListener.onClick(mNodes.get(position),  
    98.                             position);  
    99.                 }  
    100.             }  
    101.   
    102.         });  
    103.   
    104.     }  
    105.   
    106.     /** 
    107.      * 相应ListView的点击事件 展开或关闭某节点 
    108.      *  
    109.      * @param position 
    110.      */  
    111.     public void expandOrCollapse(int position) {  
    112.         Node n = mNodes.get(position);  
    113.   
    114.         if (n != null)// 排除传入参数错误异常  
    115.         {  
    116.             if (!n.isLeaf()) {  
    117.                 n.setExpand(!n.isExpand());  
    118.                 mNodes = TreeHelper.filterVisibleNode(mAllNodes);  
    119.                 notifyDataSetChanged();// 刷新视图  
    120.             }  
    121.         }  
    122.     }  
    123.   
    124.     @Override  
    125.     public int getCount() {  
    126.         return mNodes.size();  
    127.     }  
    128.   
    129.     @Override  
    130.     public Object getItem(int position) {  
    131.         return mNodes.get(position);  
    132.     }  
    133.   
    134.     @Override  
    135.     public long getItemId(int position) {  
    136.         return position;  
    137.     }  
    138.   
    139.     @Override  
    140.     public View getView(final int position, View convertView, ViewGroup parent) {  
    141.         final Node node = mNodes.get(position);  
    142.   
    143.         convertView = getConvertView(node, position, convertView, parent);  
    144.         // 设置内边距  
    145.         convertView.setPadding(node.getLevel() * 30333);  
    146.         if (!node.isHideChecked()) {  
    147.             //获取各个节点所在的父布局  
    148.             RelativeLayout myView = (RelativeLayout) convertView;  
    149.             //父布局下的CheckBox  
    150.             CheckBox cb = (CheckBox) myView.getChildAt(1);  
    151.             cb.setOnCheckedChangeListener(new OnCheckedChangeListener(){  
    152.   
    153.                 @Override  
    154.                 public void onCheckedChanged(CompoundButton buttonView,  
    155.                         boolean isChecked) {  
    156.                     TreeHelper.setNodeChecked(node, isChecked);  
    157.                     List<Node> checkedNodes = new ArrayList<Node>();  
    158.                     for(Node n:mAllNodes){  
    159.                         if(n.isChecked()){  
    160.                             checkedNodes.add(n);  
    161.                         }  
    162.                     }  
    163.                       
    164.                     onTreeNodeClickListener.onCheckChange(node,position,checkedNodes);  
    165.                     TreeListViewAdapter.this.notifyDataSetChanged();  
    166.                 }  
    167.                   
    168.             });  
    169.         }  
    170.   
    171.         return convertView;  
    172.     }  
    173.   
    174.     public abstract View getConvertView(Node node, int position,  
    175.             View convertView, ViewGroup parent);  
    176.   
    177.     /** 
    178.      * 更新 
    179.      * @param isHide 
    180.      */  
    181.     public void updateView(boolean isHide){  
    182.         for(Node node:mAllNodes){  
    183.             node.setHideChecked(isHide);  
    184.         }  
    185.           
    186.         this.notifyDataSetChanged();  
    187.     }  
    188.   
    189. }  


    node 模型类

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. package com.example.customtreeviewdemo.bean;  
    2.   
    3. public class MyNodeBean {  
    4.     /** 
    5.      * 节点Id 
    6.      */  
    7.     private int id;  
    8.     /** 
    9.      * 节点父id 
    10.      */  
    11.     private int pId;  
    12.     /** 
    13.      * 节点name 
    14.      */  
    15.     private String name;  
    16.     /** 
    17.      *  
    18.      */  
    19.     private String desc;  
    20.     /** 
    21.      * 节点名字长度 
    22.      */  
    23.     private long length;  
    24.       
    25.       
    26.     public MyNodeBean(int id, int pId, String name) {  
    27.         super();  
    28.         this.id = id;  
    29.         this.pId = pId;  
    30.         this.name = name;  
    31.     }  
    32.       
    33.     public int getId() {  
    34.         return id;  
    35.     }  
    36.     public void setId(int id) {  
    37.         this.id = id;  
    38.     }  
    39.     public int getPid() {  
    40.         return pId;  
    41.     }  
    42.     public void setPid(int pId) {  
    43.         this.pId = pId;  
    44.     }  
    45.     public String getName() {  
    46.         return name;  
    47.     }  
    48.     public void setName(String name) {  
    49.         this.name = name;  
    50.     }  
    51.     public String getDesc() {  
    52.         return desc;  
    53.     }  
    54.     public void setDesc(String desc) {  
    55.         this.desc = desc;  
    56.     }  
    57.     public long getLength() {  
    58.         return length;  
    59.     }  
    60.     public void setLength(long length) {  
    61.         this.length = length;  
    62.     }  
    63.       
    64.       
    65. }  


    TreeHelper这个也是核心操作类,主要功能是将业务数据和节点数据进行匹配


    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. package com.example.customtreeviewdemo.tree;  
    2.   
    3. import java.lang.reflect.Field;  
    4. import java.util.ArrayList;  
    5. import java.util.List;  
    6.   
    7. import com.example.customtreeviewdemo.R;  
    8.   
    9. public class TreeHelper {  
    10.   
    11.     /** 
    12.      * 根据所有节点获取可见节点 
    13.      *  
    14.      * @param allNodes 
    15.      * @return 
    16.      */  
    17.     public static List<Node> filterVisibleNode(List<Node> allNodes) {  
    18.         List<Node> visibleNodes = new ArrayList<Node>();  
    19.         for (Node node : allNodes) {  
    20.             // 如果为根节点,或者上层目录为展开状态  
    21.             if (node.isRoot() || node.isParentExpand()) {  
    22.                 setNodeIcon(node);  
    23.                 visibleNodes.add(node);  
    24.             }  
    25.         }  
    26.         return visibleNodes;  
    27.     }  
    28.   
    29.     /** 
    30.      * 获取排序的所有节点 
    31.      *  
    32.      * @param datas 
    33.      * @param defaultExpandLevel 
    34.      * @return 
    35.      * @throws IllegalArgumentException 
    36.      * @throws IllegalAccessException 
    37.      */  
    38.     public static <T> List<Node> getSortedNodes(List<T> datas,  
    39.             int defaultExpandLevel, boolean isHide)  
    40.             throws IllegalAccessException, IllegalArgumentException {  
    41.         List<Node> sortedNodes = new ArrayList<Node>();  
    42.         // 将用户数据转化为List<Node>  
    43.         List<Node> nodes = convertData2Nodes(datas, isHide);  
    44.         // 拿到根节点  
    45.         List<Node> rootNodes = getRootNodes(nodes);  
    46.         // 排序以及设置Node间关系  
    47.         for (Node node : rootNodes) {  
    48.             addNode(sortedNodes, node, defaultExpandLevel, 1);  
    49.         }  
    50.         return sortedNodes;  
    51.     }  
    52.   
    53.     /** 
    54.      * 把一个节点上的所有的内容都挂上去 
    55.      */  
    56.     private static void addNode(List<Node> nodes, Node node,  
    57.             int defaultExpandLeval, int currentLevel) {  
    58.   
    59.         nodes.add(node);  
    60.         if (defaultExpandLeval >= currentLevel) {  
    61.             node.setExpand(true);  
    62.         }  
    63.   
    64.         if (node.isLeaf())  
    65.             return;  
    66.         for (int i = 0; i < node.getChildrenNodes().size(); i++) {  
    67.             addNode(nodes, node.getChildrenNodes().get(i), defaultExpandLeval,  
    68.                     currentLevel + 1);  
    69.         }  
    70.     }  
    71.   
    72.     /** 
    73.      * 获取所有的根节点 
    74.      *  
    75.      * @param nodes 
    76.      * @return 
    77.      */  
    78.     public static List<Node> getRootNodes(List<Node> nodes) {  
    79.         List<Node> rootNodes = new ArrayList<Node>();  
    80.         for (Node node : nodes) {  
    81.             if (node.isRoot()) {  
    82.                 rootNodes.add(node);  
    83.             }  
    84.         }  
    85.   
    86.         return rootNodes;  
    87.     }  
    88.   
    89.     /** 
    90.      * 将泛型datas转换为node 
    91.      *  
    92.      * @param datas 
    93.      * @return 
    94.      * @throws IllegalArgumentException 
    95.      * @throws IllegalAccessException 
    96.      */  
    97.     public static <T> List<Node> convertData2Nodes(List<T> datas, boolean isHide)  
    98.             throws IllegalAccessException, IllegalArgumentException {  
    99.         List<Node> nodes = new ArrayList<Node>();  
    100.         Node node = null;  
    101.   
    102.         for (T t : datas) {  
    103.             int id = -1;  
    104.             int pId = -1;  
    105.             String name = null;  
    106.   
    107.             Class<? extends Object> clazz = t.getClass();  
    108.             Field[] declaredFields = clazz.getDeclaredFields();  
    109.             /** 
    110.              * 与MyNodeBean实体一一对应 
    111.              */  
    112.             for (Field f : declaredFields) {  
    113.                 if ("id".equals(f.getName())) {  
    114.                     f.setAccessible(true);  
    115.                     id = f.getInt(t);  
    116.                 }  
    117.   
    118.                 if ("pId".equals(f.getName())) {  
    119.                     f.setAccessible(true);  
    120.                     pId = f.getInt(t);  
    121.                 }  
    122.   
    123.                 if ("name".equals(f.getName())) {  
    124.                     f.setAccessible(true);  
    125.                     name = (String) f.get(t);  
    126.                 }  
    127.   
    128.                 if ("desc".equals(f.getName())) {  
    129.                     continue;  
    130.                 }  
    131.   
    132.                 if ("length".equals(f.getName())) {  
    133.                     continue;  
    134.                 }  
    135.   
    136.                 if (id == -1 && pId == -1 && name == null) {  
    137.                     break;  
    138.                 }  
    139.             }  
    140.   
    141.             node = new Node(id, pId, name);  
    142.             node.setHideChecked(isHide);  
    143.             nodes.add(node);  
    144.         }  
    145.   
    146.         /** 
    147.          * 比较nodes中的所有节点,分别添加children和parent 
    148.          */  
    149.         for (int i = 0; i < nodes.size(); i++) {  
    150.             Node n = nodes.get(i);  
    151.             for (int j = i + 1; j < nodes.size(); j++) {  
    152.                 Node m = nodes.get(j);  
    153.                 if (n.getId() == m.getpId()) {  
    154.                     n.getChildrenNodes().add(m);  
    155.                     m.setParent(n);  
    156.                 } else if (n.getpId() == m.getId()) {  
    157.                     n.setParent(m);  
    158.                     m.getChildrenNodes().add(n);  
    159.                 }  
    160.             }  
    161.         }  
    162.   
    163.         for (Node n : nodes) {  
    164.             setNodeIcon(n);  
    165.         }  
    166.         return nodes;  
    167.     }  
    168.   
    169.     /** 
    170.      * 设置打开,关闭icon 
    171.      *  
    172.      * @param node 
    173.      */  
    174.     public static void setNodeIcon(Node node) {  
    175.         if (node.getChildrenNodes().size() > 0 && node.isExpand()) {  
    176.             node.setIcon(R.drawable.tree_expand);  
    177.         } else if (node.getChildrenNodes().size() > 0 && !node.isExpand()) {  
    178.             node.setIcon(R.drawable.tree_econpand);  
    179.         } else  
    180.             node.setIcon(-1);  
    181.     }  
    182.   
    183.     public static void setNodeChecked(Node node, boolean isChecked) {  
    184.         // 自己设置是否选择  
    185.         node.setChecked(isChecked);  
    186.         /** 
    187.          * 非叶子节点,子节点处理 
    188.          */  
    189.         setChildrenNodeChecked(node, isChecked);  
    190.         /** 父节点处理 */  
    191.         setParentNodeChecked(node);  
    192.     }  
    193.   
    194.     /** 
    195.      * 非叶子节点,子节点处理 
    196.      */  
    197.     private static void setChildrenNodeChecked(Node node, boolean isChecked) {  
    198.         node.setChecked(isChecked);  
    199.         if (!node.isLeaf()) {  
    200.             for (Node n : node.getChildrenNodes()) {  
    201.                 // 所有子节点设置是否选择  
    202.                 setChildrenNodeChecked(n, isChecked);  
    203.             }  
    204.         }  
    205.     }  
    206.   
    207.     /** 
    208.      * 设置父节点选择 
    209.      *  
    210.      * @param node 
    211.      */  
    212.     private static void setParentNodeChecked(Node node) {  
    213.   
    214.         /** 非根节点 */  
    215.         if (!node.isRoot()) {  
    216.             Node rootNode = node.getParent();  
    217.             boolean isAllChecked = true;  
    218.             for (Node n : rootNode.getChildrenNodes()) {  
    219.                 if (!n.isChecked()) {  
    220.                     isAllChecked = false;  
    221.                     break;  
    222.                 }  
    223.             }  
    224.   
    225.             if (isAllChecked) {  
    226.                 rootNode.setChecked(true);  
    227.             } else {  
    228.                 rootNode.setChecked(false);  
    229.             }  
    230.             setParentNodeChecked(rootNode);  
    231.         }  
    232.     }  
    233.   
    234. }  


    核心的代码就是这些,希望对大家有帮助。


    转自:http://blog.csdn.net/shaoyezhangliwei/article/details/52275130

    展开全文
  • 完美解决word多级列表的编号不显示问题

    完美解决word多级列表的编号不显示问题

    参考文章:

    (1)完美解决word多级列表的编号不显示问题

    (2)https://www.cnblogs.com/yczcc/p/9180186.html


    备忘一下。


    展开全文
  • 前言不得不吐槽一下产品....传送门先看看效果:两的效果:三的效果:全部展开的效果(我写了五)没设计布局,比较丑,哈哈. ————————————分割线————————————–说说为什么写这货吧:公司产

    前言

    不得不吐槽一下产品.
    尼玛为啥要搞这样的功能…
    搞个两级的不就好了嘛…自带控件,多好.
    三级,四级,听说还有六级的…
    这样丧心病狂的设计,后台也不好给数据吧.

    2018年更新:

    由于迭代了很多版本,老的文章内容已经不适用,更新一下.

    效果及实现代码:

    以下实现都只用一个RecycerView,没有嵌套.

    三级列表:

    Paste_Image.png

    购物车:

    image.png

    分类快速定位:

    image.png

    综合(头部,侧滑,定位,折叠):

    image.png

    多样式列表:

    image.png

    如何使用,这里只列出折叠的使用方法:

    一.你需要创建一个adapter:

     //根据item的状态展示,可折叠
       TreeRecyclerAdapter treeRecyclerAdapter = new TreeRecyclerAdapter(TreeRecyclerType.SHOW_EXPAND);
    

    二.你需要选择一种展开方式

    image.png

       public TreeRecyclerAdapter() {
            this(null);
        }
    
        public TreeRecyclerAdapter(TreeRecyclerType treeRecyclerType) {
            type = treeRecyclerType == null ? TreeRecyclerType.SHOW_DEFAULT : treeRecyclerType;
        }
    

    构造函数传入,不传默认则使用SHOW_DEFAULT.

    三.写具体展示的item

    注意! 使用这个,没有写ViewHolder的概念,只有TreeItem和TreeItemGroup

    简单的TreeItemGroup示例,第二级 市:
    /**
    * 城市
     */
    public class CountyItemParent extends TreeItemGroup<ProvinceBean.CityBean> {//泛型代表绑定的javabean
        
        //创建子TreeItem.
        @Override
        public List<TreeItem> initChildList(ProvinceBean.CityBean data) {
            return ItemHelperFactory.createItems(data.getAreas(),  this);
        }
    
        //该级具体展示的Layout
        @Override
        public int getLayoutId() {
            return R.layout.item_two;
        }
    
        //view和data绑定
        @Override
        public void onBindViewHolder(@NonNull ViewHolder holder) {
            holder.setText(R.id.tv_content, data.getCityName());
        }
    }
    

    简单的TreeItem示例,第三级城市:
    /**
    * 县
     */
    public class AreaItem extends TreeItem<ProvinceBean.CityBean.AreasBean> {//泛型代表绑定的javabean
    
        //这个item的具体展示layout
        @Override
        public int getLayoutId() {
            return R.layout.item_three;
        }
        //这个Item条目的视图绑定操作,
        @Override
        public void onBindViewHolder(@NonNull ViewHolder holder) {
            holder.setText(R.id.tv_content, data.getAreaName());
        }
        //这个Item,在RecyclerView的每行所占比,只有RecyclerView设置了GridLayoutManager才会生效.
        //这个最好是返回能整出的数.之所以用除法,是为了可以做到,只改变GridLayoutManager的总数,无需改变Item
        @Override
        public int getSpanSize(int maxSpan) {
            return maxSpan / 6;
        }
    }
    
    

    第一级为啥没写呢? 因为写法和第二级一样的,就不写出来了.具体见demo

    怎么创建Item呢?

    有两种方法:

    1.在javabean上使用注解:
     @TreeDataType(iClass = AreaItem.class)
      public class AreasBean{
      ...
      }
    

    然后重写在TreeItemGroup中initChildList()

      @Override
        public List<TreeItem> initChildList(ProvinceBean.CityBean data) {
            return ItemHelperFactory.createItems(data.getAreas(),  this);
        }
    
    

    这样,item就生成了.

    2.直接传入item的class,创建item
     //创建item
     List<TreeItem> provinceItemList = ItemHelperFactory.createItems(cityBeen, ProvinceItemParent.class, null);
     List<TreeItem> items = ItemHelperFactory.createItems(cityBeen, null);
    

    这2行代码,效果上是一样的.


    四.如何更新adapter:

    image.png

    五,如何设置点击:

    条目点击

    1.重写TreeItemonClick():
    image.png
    2.adapter设置setOnItemClickListener

     adapter.setOnItemClickListener(new BaseRecyclerAdapter.OnItemClickListener() {
                @Override
                public void onItemClick(@NonNull ViewHolder viewHolder, int position) {
           
                }
            });
    

    注意.二者冲突


    下面附上github地址,里面有Demo,

    传送门:TreeRecyclerView
    欢迎Star,哈哈

    您的喜欢与回复是我最大的动力,欢迎评论补充.

    展开全文
  • 多级列表样式技巧(

    千次阅读 2015-12-25 20:21:23
    描述:一级列表为横向多排自适应列表,点击一级列表上面覆盖二级列表,垂直方向随动,水平方向固定。 上衣 裤子 鞋子 运动装 品牌 女装 男装 衬衫 背心 西装 运动服 西装 童装 鞋子 运动装 ...
  • 常见的办法是:光标置于标题前方,按ctrl+⬅️,编号消失位置出现小条灰色,再按ctrl+shift+S“重新应用样式”-“确定”即可找回编号。但下次打开文档这个问题可能还依然存在。 所以比较简单且有效的方法是: ...
  • WORD中的多级列表详解

    千次阅读 2020-03-23 16:53:59
    有了上面的基础,再来理解WORD中的多级列表就容易多了。 多级列表菜单 开始-段落:多级列表下拉菜单,其中的主要内容跟“项目符号”和“编号”类似。重点是“定义新的多级列表” 定义新的多级列表 打开...
  • 编辑多级列表的对话框,预览中可以看到正确的自动编号格式,导航窗也显示正确,但是在正式的文档中自动编号都是黑条
  • 表A(id,name,typeid) ...第种:用CASE WHEN THEN判断 SELECT CASE WHEN b.parentid IS NULL THEN b.tname WHEN b1.typeid IS NOT NULL THEN b1.tname+'/'+b.tyname ELSE b2.tname+'/'+b1.tname+'/'+
  • android多级树形列表

    万次阅读 热门讨论 2016-11-16 10:09:34
    我们开发app过程中,经常会碰到需要 多级列表展示的效果。而android原生sdk中根本没有3 4甚至更多级别的列表控件。
  • Android多级列表的实现

    千次阅读 2019-05-14 17:38:46
    一级列表窗口 /** * 第一级列表 * 1.编辑状态下选中一个条目,会弹出底部操作栏 * 2.非编辑状态下选中条目会跳转到下一级 * 3.复选框使用ImageView而不是CheckBox * 4.编辑状态下,按返回键回到非编辑...
  • 安卓多级列表简单实现

    千次阅读 2016-03-17 11:30:47
    listview我们可以使用expandablelistview,可以解决问题,但是要是多级的listview我们该怎么办。  网上有个办法就是expandablelistview嵌套expandablelistview,我曾经以为这个可以解决问题,但是在实际应用...
  • vue中递归组件实现多级列表

    千次阅读 2020-01-01 23:17:36
    、递归组件的概念 递归组件: 递归组件简单来说在组件...而如果使用递归组件,就可以次性解决,嵌套层级简单,可以实现多级列表。 二、递归组件的实现 父组件的data数据 name: 'Home' data () { return { ...
  • Word2016设置多级列表

    万次阅读 2018-05-13 16:10:27
    笨呀,折腾了两天才解决问题...注意:多级列表在“开始”菜单里面。--&gt;在这个属性界面同样的方式设置二标题:你有多少设置多少。设置完成“确认”。结果如图:遗憾的是:第二章的编号依然以1.x开始。下...
  • STM32 oled多级菜单显示

    千次阅读 多人点赞 2021-03-05 16:41:54
    前言 只要有显示屏的地方,就要用到多级菜单的显示。在很多初学者眼里,多级菜单的显示是很难的,今天我做完了这个小项目,我就来分享一下我做的经历。 首先肯定的是,只要理清思路,... 一级菜单 二级菜单 ...
  • 多级分类列表查询

    千次阅读 2019-09-03 11:24:35
    在数据库中,使用parent_id标签,将父id和子列表关联起来。 面包屑导航 实现思路将浏览的记录,标记放到$scope中进行保存,用entity1,entity2…进行区分 1 修改 itemCatController.js $scope.grade=1;//默认为 1 ...
  • --第一级数据--> < view class = "flex-wrp workitemlist"> < view class = "flex-item"> < text class = 'content'> {{workitem.name}} text > < view class = "flex-item"> < ...
  • 在有序列表中间插入文本、段落、代码块等等都会出现序号错乱的情况。应如下解决: 如下所示: 第个标题 第个小标题 ...②如果要添加二或者其他代码块啊啥的,要记得在下行中先敲个[TAB]键然后再重
  • Android多级树形选择列表

    千次阅读 2018-07-13 16:39:30
    项目中有多个地方要用到多级列表的菜单,最开始我用的是ExpandableListView,但问题是ExpandableListView支持两级列表,于是我就用ExpandableListView嵌套ExpandableListView,但非常麻烦,而且关键的是具体分几级...
  • 首先,理清思路,我们的目标:在bootstrap上显示后台回传的json数据里的多级数组。 这里的步骤可以大致分为:、在后套controller中写好方法,向前台return个JSONString 二、在前台jsp中,使用ajax接收后台...
  • 实现word的多级列表功能

    千次阅读 2016-05-22 14:45:41
    在使用vsto开发word插件的时候,需要实现word的多级列表的功能,如,然后再word中录制宏,看vba代码,然后再转换成c#代码。 如下列vba代码: With ListGalleries(wdOutlineNumberGallery).ListTemplates(1)....
  • 更快实现Android多级树形选择列表

    千次阅读 2017-01-15 15:51:11
    快速实现Android多级树形列表,这个库是在... 支持多级复选框选中,使用行代码。 3. 支持动态更新数据并保持原有展开/关闭状态。 4. 支持ListView、RecyclerView。 项目地址:https://github.com/zhangk
  • 今天在写文档时,发现WORD5的标题都变黑块了,找了度娘的资料,终于解决了。 第种 1、光标bai放在黑快的右边,按向左的箭头,然后ctrl+shift+s,点击重新应用。 2、点击“定义新的多级列表”(不知道从哪儿找...
  • 描述:win10系统word2019显示目录只显示部分一级二级解决办法 步骤: 引用->目录->自定义目录 目录->显示级别->选择想要显示到的级别->确认
  • 关于word中多级列表使用的笔记

    千次阅读 2019-03-19 19:11:51
    经常遇到编号不能连续,尤其是下一级不能和上一级起来,在中间手动插入一个新的标题,编号也不能自动更正的问题 一、 xxxx  二、 xxxx  三、 xxxx  1.1xxx(这里应该是3.1xxx了,就是这个问题很纠结)
  • Android UI 之实现多级列表TreeView

    千次阅读 2017-03-01 17:49:16
    所谓TreeView就是在Windows中常见的多级列表树,在Android中系统默认提供了ListView和ExpandableListView两种列表,最多支持到二级列表的实现,所以如果想要实现三级和更多层次的列表,就需要我们自己来做一些...
  • 看下u-view是如何写的 只要后台返回的数据格式是一样的,然后我们就可以展现多级联动的效果!value也要一致就OK啦!
  • Android中多级树形列表

    千次阅读 2018-04-07 16:15:02
    次开发中,碰到了多级树形列表的问题,不是我们平时使用的ExpandListView这种只有子父类两列表,而是层级更深。 推荐几个可以参考的博客: 1、鸿神的ListView实现多级树形列表 2、个兄弟在鸿神的基础上...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 33,126
精华内容 13,250
关键字:

多级列表只显示一级