ExpandableListView的自定义布局以及注意事项

来源:互联网 发布:萧山三中网络课程 编辑:程序博客网 时间:2024/06/08 14:32

android开发中常常需要使用到ExpandableListView来对一组数据进行分组, 使用ExpandableListView能够达到类似QQ分组的效果,类似于下面两张效果图:
这里写图片描述
这里写图片描述

要达到这种效果其实并不难,因为ExpandableListView跟ListView很相似,如果你对ListView很熟悉的话,很快就能掌握它,如果对ListView不熟悉的话,建议 先看看之前的博文 android学习之ListView的基本使用

首先定义一个主布局:activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">   <ExpandableListView       android:id="@+id/expandableView"       android:layout_width="wrap_content"       android:layout_height="wrap_content"></ExpandableListView></RelativeLayout>

然后自定义ExpandableListView中的组名显示布局:item_group.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical" android:layout_width="match_parent"    android:layout_height="match_parent">    <TextView        android:id="@+id/tv_group_title"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentLeft="true"        android:layout_centerInParent="true"        android:text="title"        android:textSize="30sp"        android:layout_marginLeft="30dp"        />    <ImageView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:id="@+id/iv_group_img"        android:layout_alignParentRight="true"/></RelativeLayout>

接着定义每个组下子项的布局:item_child.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical" android:layout_width="match_parent"    android:layout_height="match_parent">    <TextView        android:id="@+id/tv_child_title"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_marginLeft="16dp"        android:layout_marginTop="30dp"        android:textSize="20sp"        android:layout_alignParentLeft="true"        android:text="test"/>    <TextView        android:id="@+id/tv_child_explain"        android:layout_width="wrap_content"        android:layout_alignLeft="@id/tv_child_title"        android:layout_below="@id/tv_child_title"        android:layout_height="wrap_content"        android:text="explain"/>    <ImageView        android:id="@+id/iv_child_img"        android:layout_alignParentRight="true"        android:layout_width="wrap_content"        android:layout_height="wrap_content" /></RelativeLayout>

为了方便,可以建立一个类为每个布局的组件创建一个字段,如给子项定义一个Child类:

/** * Created by mhwang on 2015/11/25. */public class Child {    /**子项标题*/    private String title;    /**子项解释*/    private String explain;    public Child(){        title = "title";        explain = "explain";    }    public String getTitle() {        return title;    }    public String getExplain() {        return explain;    }    public void setTitle(String title) {        this.title = title;    }    public void setExplain(String explain) {        this.explain = explain;    }}

如果需要,也可以为群组建立类。

然后到了关键部分,为ExpandableListView创建一个适配器,适配器是连接视图与数据的桥梁。负责将数据送到视图中。这里自定义MyAdapter适配器继承BaseExpandableListAdapter,并重写其所有方法。

/** * Created by mhwang on 2015/11/25. */public class MyAdapter extends BaseExpandableListAdapter {    /**群组名*/    private ArrayList<String> groups;    /**群组下的子项*/    private ArrayList<ArrayList<Child>> childs;    private Context mContext;    public MyAdapter(Context context){        mContext = context;        init();    }    /**为了测试方便,先初始化一些数据*/    public void init(){        groups = new ArrayList<String>();        //添加一些群组        for(int i = 0; i < 10; i++){            groups.add("群组"+i);        }        childs = new ArrayList<ArrayList<Child>>();        //为每个群组添加一些子项        for(int i = 0; i < groups.size(); i++){            //如果该群组是偶数,为其添加5个子项,奇数添加3项            ArrayList<Child> values = new ArrayList<>();            if(i % 2 == 0 ){                for(int j = 0; j < 5; j++) {                    Child child = new Child();                    child.setTitle("子项"+j);                    child.setExplain("解释"+j);                    values.add(child);                    childs.add(values);                }            }else{                for(int j = 0; j < 3; j++){                    Child child = new Child();                    child.setTitle("子项"+j);                    child.setExplain("解释"+j);                    values.add(child);                    childs.add(values);                }            }        }    }    @Override    public int getGroupCount() {        return groups.size();    }    @Override    public int getChildrenCount(int groupPosition) {        return childs.get(groupPosition).size();    }    @Override    public Object getGroup(int groupPosition) {        return groups.get(groupPosition);    }    @Override    public Object getChild(int groupPosition, int childPosition) {        return childs.get(groupPosition).get(childPosition);    }    @Override    public long getGroupId(int groupPosition) {        return groupPosition;    }    @Override    public long getChildId(int groupPosition, int childPosition) {        return childPosition;    }    @Override    public boolean hasStableIds() {        return true;    }    @Override    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {        /**创建view */        View v = LayoutInflater.from(mContext).inflate(R.layout.item_group,null);        /**通过创建的view与自定义布局绑定,就要以找到布局里的组件了*/        TextView tvGroupTitle = (TextView)v.findViewById(R.id.tv_group_title);        ImageView ivGroupImg = (ImageView)v.findViewById(R.id.iv_group_img);        tvGroupTitle.setText(groups.get(groupPosition));        ivGroupImg.setBackgroundResource(R.drawable.m1);        return v;    }    @Override    public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {        View v = LayoutInflater.from(mContext).inflate(R.layout.item_child,null);        TextView tvChildTitle = (TextView)v.findViewById(R.id.tv_child_title);        TextView tvChildExplain = (TextView)v.findViewById(R.id.tv_child_explain);        ImageView ivChildImg = (ImageView)v.findViewById(R.id.iv_child_img);        tvChildTitle.setText(childs.get(groupPosition).get(childPosition).getTitle());        tvChildExplain.setText(childs.get(groupPosition).get(childPosition).getExplain());        ivChildImg.setBackgroundResource(R.drawable.m2);        return v;    }    @Override    public boolean isChildSelectable(int groupPosition, int childPosition) {        return true;    }}

最后一步,在MainActivity中获取ExpandableListView实例并调用其setAdapter方法将自定义的MyAdapter对象传进去即可。

public class MainActivity extends AppCompatActivity {    ExpandableListView expandableListView;    MyAdapter adapter;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        expandableListView = (ExpandableListView)findViewById(R.id.expandableView);        adapter = new MyAdapter(this);        expandableListView.setAdapter(adapter);    }}

这里有几点值得注意:
1、与ListView不同,在ExpandableListView中使用ViewHolder的话会出问题,因为ExpandableListView中的每一个组下子项数目并不是相同的,重用之前的convertView会崩溃。
2、如果是从外部读入数据到列表项中,如数据库等,要特别注意列表项数据为null的情形,否则会有空指针异常并崩溃。

0 0
原创粉丝点击