Android中多级列表可以使用ExpandableListView和SimpleExpandableListAdapter配合来实现,但是,SimpleExpandableListAdapter用起来挺麻烦的,不易理解,而且扩展性也不好,因此,自定义BaseExpandableListAdapter类的子类以及封装相关的操作,用起来会更加直观和方便,我把我设计的封装贴出来供新手参考吧。


   首先上效果图,如图所示:


224351468.png


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交流,或者关注我的新浪微博 @卢_俊 获取最新的文章和资讯。