Android中多级列表可以使用ExpandableListView和SimpleExpandableListAdapter配合来实现,但是,SimpleExpandableListAdapter用起来挺麻烦的,不易理解,而且扩展性也不好,因此,自定义BaseExpandableListAdapter类的子类以及封装相关的操作,用起来会更加直观和方便,我把我设计的封装贴出来供新手参考吧。
首先上效果图,如图所示:
1. 首先设计多级列表的标题类
就像文件和文件夹可以统一地用File类来抽象一样,多级列表的一级标题和二级标题其实也可以用同一个基类来抽象,因此,我设计了一个基类和两个子类,GroupList,GroupListChild 和 GroupListParent,其实现如下所示:
(1) GroupList 多级列表标题的抽象基类
public abstract class GroupList {
private final String mTitle;
public GroupList(String title) {
mTitle = title;
}
public String getTitle() {
return mTitle;
}
public abstract List<GroupList> getChild();
public abstract int getResource();
public abstract void buildView(View v);
}
(2) GroupListChild 多级列表二级标题子类
public class GroupListChild extends GroupList {
public GroupListChild(String title) {
super(title);
}
@Override
public int getResource() {
return R.layout.grouplist_child;
}
@Override
public List<GroupList> getChild() {
return null;
}
@Override
public void buildView(View v) {
TextView textView = (TextView)v.findViewById(R.id.GroupListChild);
textView.setText(getTitle());
}
}
(3) GroupListParent 多级列表一级标题子类
public class GroupListParent extends GroupList {
private List<GroupList> mPopListChilds;
public GroupListParent(String title,List<GroupList> childs) {
super(title);
mPopListChilds = childs;
}
@Override
public int getResource() {
return R.layout.grouplist_parent;
}
@Override
public List<GroupList> getChild() {
return mPopListChilds;
}
@Override
public void buildView(View v) {
TextView textView = (TextView)v.findViewById(R.id.GroupListParent);
textView.setText(getTitle());
}
}
2. 设计BaseExpandableListAdapter的子类
我设计的子类是一种通用的Adapter子类,类的实现中并不包含具体的Layout实现,所有的Layout都由GroupList的getResource和buildView来负责,因此,可以非常灵活地修改Layout的具体实现,而不用修改Adapter的代码。
public class GroupListAdapter extends BaseExpandableListAdapter {
private Context mContext;
private List<GroupList> mGroups;
public GroupListAdapter(Context context, List<GroupList> groups) {
this.mContext = context;
this.mGroups = groups;
}
@Override
public Object getChild(int groupPosition, int childPosition) {
List<GroupList> chList = mGroups.get(groupPosition).getChild();
if( chList == null) {
return null;
}
return chList.get(childPosition);
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View view,ViewGroup parent) {
GroupList child = (GroupList)getChild(groupPosition, childPosition);
if( child == null) {
return null;
}
if (view == null) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = (RelativeLayout)inflater.inflate(child.getResource(), null);
}
child.buildView(view);
return view;
}
@Override
public int getChildrenCount(int groupPosition) {
List<GroupList> chList = mGroups.get(groupPosition).getChild();
if( chList == null) {
return 0;
}
return chList.size();
}
@Override
public Object getGroup(int groupPosition) {
return mGroups.get(groupPosition);
}
@Override
public int getGroupCount() {
return mGroups.size();
}
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public View getGroupView(int groupPosition, boolean isLastChild, View view,ViewGroup parent) {
GroupList group = (GroupList)getGroup(groupPosition);
if (view == null) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = (RelativeLayout)inflater.inflate(group.getResource(), null);
}
group.buildView(view);
return view;
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public boolean isChildSelectable(int arg0, int arg1) {
return true;
}
}
3. 应用代码
为了简化,我就直接在MainActivity中使用上述封装的类来完成多级列表的功能演示,示例如下:
public class MainActivity extends Activity implements OnGroupClickListener,OnChildClickListener {
private ExpandableListView mlistView;
private GroupListAdapter mAdapter;
private static final String[] mParentMenu = {
"Book", "Video", "Audio"
};
private static final String[][] mChildMenu = {
{ "book1", "book2", "book3", "book4" },
{ "video1", "video2" },
{ "audio1", "audio2", "audio3","audio4"}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mlistView = new ExpandableListView(this);
mlistView.setOnGroupClickListener(this);
mlistView.setOnChildClickListener(this);
List<GroupList> groups = new ArrayList<GroupList>();
for( int i=0; i<mParentMenu.length; i++) {
List<GroupList> childs = new ArrayList<GroupList>();
for( int j=0; j<mChildMenu[i].length; j++ ) {
childs.add(new GroupListChild(mChildMenu[i][j]));
}
groups.add(new GroupListParent(mParentMenu[i],childs));
}
mAdapter = new GroupListAdapter(this,groups);
mlistView.setAdapter(mAdapter);
setContentView(mlistView);
}
@Override
public boolean onChildClick(ExpandableListView parent, View v,int groupPosition, int childPosition, long id) {
return false;
}
@Override
public boolean onGroupClick(ExpandableListView parent, View v,int groupPosition, long id) {
return false;
}
}
4. 相关的xml文件
(1) grouplist_child.xml 文件
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <TextView android:id="@+id/GroupListChild" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#FFFF0000" android:layout_margin="10dp" android:layout_centerInParent="true"/> </RelativeLayout>
(2) grouplist_parent.xml 文件
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <TextView android:id="@+id/GroupListParent" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@android:color/black" android:textStyle="bold" android:layout_margin="10dp" android:layout_centerInParent="true"/> </RelativeLayout>
5. 总结
本文给出了Android多级列表的封装与应用的示例,个人感觉这样封装的设计可扩展性挺好的,特别是两个特点:1. 屏蔽了一级标题和二级标题的差异,统一接口;2. 将layout均放到Adapter的Item的类中去实现,让Adapter与layout脱离耦合。这两种设计思路,相信在以后的软件设计中也会经常用到。整个工程的代码在附件中,代码结构还算清楚,就不用过多解释啦,有疑问欢迎留言或者来信lujun.hust@gmail.com交流,或者关注我的新浪微博 @卢_俊 获取最新的文章和资讯。