ExpandableListView的使用和理解

来源:互联网 发布:网络无法登陆暴雪 编辑:程序博客网 时间:2024/06/06 09:58

ExpandableListView顾英文思意:可扩展列表视图。

之前一直看别人用这个控件,哇,觉得肯定很复杂,数据也很复杂吧,也就一直没尝试用到这个控件,就和我对自定义View是一样的感觉,是新手必经之路,又很怕去触碰,觉得比较难,放在以后再说,但是,建议,没有什么难不难,去理解,去写控件的代码,走一遍,想想,就理解了。言归正传:

ExpandableListView 就是ListView的进化版,满足了一般ListView做不到的事情,如现在的QQ好友列表的样式,点击拉伸扩展,再点击缩小,着就是父item和子item的关系了。

首先,先看看主布局:activity_main.xml:

   <ExpandableListView        android:id="@+id/expanda_list"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:cacheColorHint="#000000" />

仅此而已,外层你可以用LinearLayout也好,或者是最新的ConstraintLayout布局(约束布局)也好等等,都可以。

其次要需要创建两个xml布局,一个是父Item,一个是子Item,所有的只需要这两个布局去实现,因为我们有Holder呀,一个这么神奇复用的东西对吧~
父布局.xml:

<?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="70dp"    android:orientation="horizontal">    <RelativeLayout        android:layout_width="match_parent"        android:layout_height="70dp">        <ImageView            android:id="@+id/img"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_centerVertical="true"            android:layout_marginLeft="20dp" />        <TextView            android:id="@+id/txt"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_centerVertical="true"            android:layout_marginLeft="20dp"            android:layout_toRightOf="@+id/img"            android:text="张三"            android:textSize="18sp" />        <TextView            android:id="@+id/txt2"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_alignParentRight="true"            android:layout_centerVertical="true"            android:layout_marginRight="20dp"            android:gravity="right"            android:text="4/17" />    </RelativeLayout></LinearLayout>

子布局xml:.

<?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="70dp"    android:padding="3dp"    android:orientation="horizontal">    <ImageView        android:id="@+id/img"        android:layout_width="50dp"        android:layout_height="50dp"        android:layout_marginLeft="20dp"        android:src="@drawable/ic_launcher" />    <LinearLayout        android:layout_width="match_parent"        android:layout_height="70dp"        android:gravity="center_vertical"        android:orientation="vertical">        <TextView            android:id="@+id/txt"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="皮皮护法" />        <TextView            android:id="@+id/txt2"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_marginTop="10dp"            android:text="哇,皮皮虾,我们走我们走" />    </LinearLayout></LinearLayout>

不要觉得看起来很多,这只是为了效果,其实很多都是没有意义的属性,比如有几个textview就不会用到他,只是让他显示text而已。

一般默认的ExpandableListView的父Item都是有小箭头的,可以理解为打开与不打开有个小三角形的指示图标。

在MainActivity.java中,类似的与ListView一样,需要放入数据,需要声明这个ExpandableListView控件,还需要一个适配器,以及两个复用的Holder就足够了。
我的代码有点乱,但是记住两个核心:
1. 一个List group = new ArrayList<>();这样的List是专门为父Item提供的,需要什么样的栏目,直接将数据放进该List即可。
2. 一个List《List《String》》 item_list =new ArrayList<>();这样的
List《List《String》> 是存放每个子Item相对应的数据,可以知道,item_list存放进去的是一个list<>对象,而在list对象中在放入相对应的String的数据,这个层级关系一定要理清楚。

下面是代码:

public class MainActivity extends AppCompatActivity {    private ExpandableListView expandableListView; //expandablelistview控件    private MyExpandableListViewAdapter adapter;   //适配器    private List<String> group_list = new ArrayList<>();//父item 显示的东西,加数据就多现实一栏父item 父列表    private List<String> text = new ArrayList<>();  //子item对应的文字集合    private List<Integer> tupian = new ArrayList<>();   //子item对应的图片集合    private List<List<String>> item_list = new ArrayList<>();//将子item放进来,适配进每个父Item的相对应子item    private List<List<Integer>> item_list2 = new ArrayList<>();//将子item图片放进来,适配进每个父item相对应的子item    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        /**         * 父item的栏目,多一行则多显示一行的界面数据         */        group_list.add("我的好友");        group_list.add("我的亲人");        group_list.add("我的同学");        group_list.add("我的兄弟");        /**         * 关于子item的数量,文字显示         */        text.add("皮皮虾");        text.add("石乐志");        text.add("真皮");        text.add("石乐志");        text.add("真皮");        text.add("石乐志");        /**         * 这一栏负责子item的图片显示, 所有的东西都是同步,改变12行,每个子item 1.2行都会变         */        tupian.add(R.drawable.two);        tupian.add(R.drawable.two);        tupian.add(R.drawable.two);        tupian.add(R.drawable.two);        tupian.add(R.drawable.two);        tupian.add(R.drawable.two);        item_list2.add(tupian);        item_list2.add(tupian);        item_list2.add(tupian);        item_list2.add(tupian);        item_list2.add(tupian);        item_list2.add(tupian);        /**         * 子Item的文字。和图片必须同时增加,不然就会指数越界,切记。两个同时从4行加到6行才行         */        /**         * 决定着多少个父item能被打开,加入有四个父item,但是只写三行下面的代码,。第四个父item就会指数越界         */        item_list.add(text);        item_list.add(text);        item_list.add(text);        item_list.add(text);        expandableListView = (ExpandableListView) findViewById(R.id.expanda_list);//找该控件        expandableListView.setGroupIndicator(null);        /**         * 可用lambda表达式简化,一般是需要写出来的,用lambda可省略         * 对父子item的点击操作都可以写在这里面的逻辑中         */        expandableListView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {            @Override            public boolean onGroupClick(ExpandableListView expandableListView, View view, int i, long l) {                if (item_list.get(i).isEmpty()) {                    return true;                }                return false;            }        });        expandableListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {            @Override            public boolean onChildClick(ExpandableListView expandableListView, View view, int i, int i1, long l) {                Toast.makeText(MainActivity.this, "group=" + i + "child=" + i1, Toast.LENGTH_SHORT).show();                return false;            }        });        adapter = new MyExpandableListViewAdapter(this);        expandableListView.setAdapter(adapter);    }    private class MyExpandableListViewAdapter extends BaseExpandableListAdapter {        private Context mContext;        public MyExpandableListViewAdapter(Context context) {            this.mContext = context;        }        @Override        public int getGroupCount() {            return group_list.size();        }        @Override        public int getChildrenCount(int i) {            return item_list.get(i).size();        }        @Override        public Object getGroup(int i) {            return group_list.get(i);        }        @Override        public Object getChild(int i, int i1) {            return item_list.get(i).get(i1);        }        @Override        public long getGroupId(int i) {            return i;        }        @Override        public long getChildId(int i, int i1) {            return i1;        }        @Override        public boolean hasStableIds() {            return true;        }        /**         *获得父布局的逻辑操作         */        @Override        public View getGroupView(int i, boolean b, View view, ViewGroup viewGroup) {            GroupHolder groupHolder = null;            if (view == null) {                view = LayoutInflater.from(mContext).inflate(R.layout.expendlist_group, null);                groupHolder = new GroupHolder();                groupHolder.txt = (TextView) view.findViewById(R.id.txt);                groupHolder.img = (ImageView) view.findViewById(R.id.img);                view.setTag(groupHolder);            } else {                groupHolder = (GroupHolder) view.getTag();            }            /**             * 在这里 !b表示没有被父item没有被点击。前面的横向指针图片不会变             * 如果被点击,则进入else逻辑,更换指针向下的图片             */        /*    if (!b) {                groupHolder.img.setBackgroundResource(R.drawable.two);            } else {                groupHolder.img.setBackgroundResource(R.drawable.ic_launcher);            }*/            groupHolder.txt.setText(group_list.get(i));            return view;        }        /**         * 获得子布局的逻辑         */        @Override        public View getChildView(int i, int i1, boolean b, View view, ViewGroup viewGroup) {            ItemHolder itemHolder = null;            if (view == null) {                view = LayoutInflater.from(mContext).inflate(R.layout.expendlist_item, null);                itemHolder = new ItemHolder();                itemHolder.txt = (TextView) view.findViewById(R.id.txt);                itemHolder.img = (ImageView) view.findViewById(R.id.img);                view.setTag(itemHolder);            } else {                itemHolder = (ItemHolder) view.getTag();            }            itemHolder.txt.setText(item_list.get(i).get(i1));            itemHolder.img.setBackgroundResource(item_list2.get(i).get(i1));            return view;        }        @Override        public boolean isChildSelectable(int i, int i1) {            return true;        }    }    private class GroupHolder {        TextView txt;        ImageView img;    }    private class ItemHolder {        TextView txt;        ImageView img;    }}

接下来是效果图:
这里写图片描述
这里写图片描述
我相信,代码的注释也都很清楚了,当然,不要忘记最后两个Holder,一个是对应获得父View的Holder,一个是对应子View的Holder,有所区别。剩下主要的也就是adapter的代码,无须担心,继承了BaseExpandableListAdapter之后AS会提示让你倒入这些方法,再去写就可以了。
对于上面的增加数据,我是把它写死了,那么就要注意,当增加一个子item的Text的时候,一定要增加一个相对应的子Image,因为text 和 image在我的布局是相对应一起的,如果只加一个而不管增加相对应的一个text或者image的话,就会数组越界异常,导致程序崩溃。

如果你能看到这里,我们就继续解释一下数据,上面的代码是将数据写死,如果需要时事获得数据呢?也很简单,通过从服务器获得的数据,将父item数据放入List<>中,将子Item的数据,依次add放入List<>中,在将该List<> 再次add进add进List《List》就可以了。其他的适配过程都一样。

当然,还有一种思路,这样的ExpandableListView看起来,是不是就和LinearLayout相似,是的,这样就接触到了自定义View有关的知识,自己写个Layout继承LinearLayout,然后抓取父Item 子Item的布局,通过View view = LayoutInflater.from(context).inflate(R.layout.child_layout)来抓取布局,然后自定义Layout.addView(view)是不是就行了呢。

这是粗略的一个自定义模拟ExpandableListView,可以直接从as 的 open打开,具体有想法的可以去琢磨琢磨改一改,还是挺有意思的。
http://download.csdn.net/detail/chenxuanhe1995/9787506

3 0
原创粉丝点击