06.实例篇:仿QQ好友列表——ExpandableListView和ListView(下篇)

来源:互联网 发布:淘宝平面设计 编辑:程序博客网 时间:2024/05/19 12:38

1.前言

本篇主要ExpandableListView和ListView一些基础知识点介绍,主要包括一些类和接口的使用介绍,主要是参照google 最新的API文档摘要总结的;


2.什么是ListView

是一种ViewGroup,用于滚动展示一组列表,这些列表项自动由Adapter从数据源读取数据产生特定的View填充到ListView;
当布局中的内容是动态的或者预先不可知的,可以使用AdapterView(ListView,GridView是其子类)运行时填充;
AdapterView(包括子类)使用Adapter绑定数据到自己,Adapter是数据源和AdapterView布局的中介;


3.ListView重要方法和属性:

  用于垂直滚动列表视图,列表项来自ListAdapter;
  类继承结构:具体的类
  public class  ListView  extends AbsListView 
    java.lang.Object
       ↳ android.view.View
         ↳ android.view.ViewGroup
           ↳ android.widget.AdapterView<T extends android.widget.Adapter>
                ↳ android.widget.AbsListView
                   ↳ android.widget.ListView
  直接子类:
        ExpandableListView :用于展示两级列表;
 
  重要的XML属性:
    android:divider:两个列表项之间的分割线(可以使color或者Drawable)
    android:dividerHeight:分割线的高度(厚度)
    android:entries:静态引用一个数组资源,用来填充ListView的
    android:footerDividersEnabled:对于footer view是否有divider
    android:headerDividersEnabled:
  从AbsListView继承的重要属性:
    android:choiceMode:设置列表项的选择行为,是否可以选择,是否支持多选
    android:listSelector :设置列表中被选中的项的Drawable
    android:textFilterEnabled:是否支持过滤


  重要方法:
      void  addFooterView(View v):添加固定的View到列表的底部,在setAdapter之前调用,可以添加多次,显示多个
      void addFooterView(View v, Object data, boolean isSelectable)      
      void addHeaderView(View v)
    
      ListAdapter getAdapter():返回与之绑定的Adapter
      void setAdapter (ListAdapter adapter) :设置ListView的数据

      long[] getCheckItemIds ():api8过期,获取选择的多个Items的id,仅当模式不是CHOICE_MODE_NONE.有效
      void setSelection (int position):设置选定的列表项,从0开始

4.ListView相关的类:ListAdapter(也是接口)

   public interface Adapter  android.widget.Adapter    
   间接子类:
   ArrayAdapter<T>, BaseAdapter, CursorAdapter, HeaderViewListAdapter, ListAdapter,    
   ResourceCursorAdapter, SimpleAdapter, SimpleCursorAdapter,SpinnerAdapter, WrapperListAdapter 
   方法:
   abstract int getCount():有多少数据
   abstract Object getItem(int position):获取特定位置的数据
   abstract long    getItemId(int position):获取特定位置的行id
   abstract View getView(int position, View convertView, ViewGroup parent):获取特定位置展示的View
   abstract boolean isEmpty():
  
   public interface ListAdapter implements Adapter (添加了两个抽象方法) android.widget.ListAdapter
   间接子类:
   ArrayAdapter<T>, BaseAdapter(抽象类), CursorAdapter(抽象类), HeaderViewListAdapter, 
   ResourceCursorAdapter, SimpleAdapter, SimpleCursorAdapter, WrapperListAdapter
     
   常用的Adapter:
   public class ArrayAdapter extends BaseAdapter implements Filterable:android.widget.ArrayAdapter<T>
   具体简单的Adapter类,数据源是数组,布局中有一个简单的TextView,如果想要其它View,可以重写getView方法
   使用一般重写,或者使用:
   public ArrayAdapter (Context context, int resource, T[] objects):Resource布局文件必须有特定名称的textview
   public ArrayAdapter (Context context, int resource, int textViewResourceId, T[] objects)
   public ArrayAdapter (Context context, int resource, List<T> objects)
   public ArrayAdapter (Context context, int resource, int textViewResourceId, List<T> objects)
    
   public class  SimpleCursorAdapter extends ResourceCursorAdapter:

   android.support.v4.widget.SimpleCursorAdapter

   构造器:
   SimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags)
   参数:layout-定义列表项的布局文件,c-数据源cursor,可以为null(如果不可用),
             from-数组定义了需要绑定的cursor数据列名,to-表明view的id,用来展示数据
             flags-决定adapter的行为,FLAG_AUTO_REQUERY(过期,不建议使用,会在主线程中获取数据,阻塞)                 FLAG_REGISTER_CONTENT_OBSERVER
(添加内容监听器,当通知到来,

调用onContentChanged方法,小心内存泄露,当使用CursorAdapter[CursorLoader]时,不需要该标志;

   方法:
   Cursor swapCursor(Cursor c):换入一个新的Cursor,返回旧的cursor【未关闭】,如果cursor为null或者新的和旧的一样返回null
   public abstract class  CursorAdapter  extends BaseAdapter implements Filterable


5.ListView使用方式:【读取本地数据】

  •     需要ListView;
  •    需要ListAdapter及其子类;
  •    如果Adpater数据发生变化,应该调用notifyDataSetChanged()方法;
   ListView+ArrayAdapter方法:
   定制每一项文本内容,可以重写数组中每个对象的toString方法;
   定制ListView每一项的视图,可以重写getView方法;
   ArrayAdapter adapter = new ArrayAdapter<String>(this,        android.R.layout.simple_list_item_1, myStringArray);   ListView listView = (ListView) findViewById(R.id.listview);   listView.setAdapter(adapter);

   ListView+SimpleCursorAdapter方法:
   String[] fromColumns = {ContactsContract.Data.DISPLAY_NAME,                        ContactsContract.CommonDataKinds.Phone.NUMBER};   int[] toViews = {R.id.display_name, R.id.phone_number};   SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,         R.layout.person_name_and_number, cursor, fromColumns, toViews, 0);   ListView listView = getListView();   listView.setAdapter(adapter);

   处理点击事件:实现AdapterView.onItemClickListener接口
<pre name="code" class="java">    // Create a message handling object as an anonymous class.    private OnItemClickListener mMessageClickedHandler = new OnItemClickListener() {        public void onItemClick(AdapterView parent, View v, int position, long id) {        // Do something in response to the click        }    };    listView.setOnItemClickListener(mMessageClickedHandler); 
   使用CursorLoader+ListView方法:   
  public class ListViewLoader extends ListActivity        implements LoaderManager.LoaderCallbacks<Cursor> {    // This is the Adapter being used to display the list's data    SimpleCursorAdapter mAdapter;    // These are the Contacts rows that we will retrieve    static final String[] PROJECTION = new String[] {ContactsContract.Data._ID,            ContactsContract.Data.DISPLAY_NAME};    // This is the select criteria    static final String SELECTION = "((" +             ContactsContract.Data.DISPLAY_NAME + " NOTNULL) AND (" +            ContactsContract.Data.DISPLAY_NAME + " != '' ))";    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        // Create a progress bar to display while the list loads        ProgressBar progressBar = new ProgressBar(this);        progressBar.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,                LayoutParams.WRAP_CONTENT, Gravity.CENTER));        progressBar.setIndeterminate(true);        getListView().setEmptyView(progressBar);        // Must add the progress bar to the root of the layout        ViewGroup root = (ViewGroup) findViewById(android.R.id.content);        root.addView(progressBar);        // For the cursor adapter, specify which columns go into which views        String[] fromColumns = {ContactsContract.Data.DISPLAY_NAME};        int[] toViews = {android.R.id.text1}; // The TextView in simple_list_item_1        // Create an empty adapter we will use to display the loaded data.        // We pass null for the cursor, then update it in onLoadFinished()        mAdapter = new SimpleCursorAdapter(this,                 android.R.layout.simple_list_item_1, null,                fromColumns, toViews, 0);        setListAdapter(mAdapter);        // Prepare the loader.  Either re-connect with an existing one,        // or start a new one.        getLoaderManager().initLoader(0, null, this);    }    // Called when a new Loader needs to be created    public Loader<Cursor> onCreateLoader(int id, Bundle args) {        // Now create and return a CursorLoader that will take care of        // creating a Cursor for the data being displayed.        return new CursorLoader(this, ContactsContract.Data.CONTENT_URI,                PROJECTION, SELECTION, null, null);    }    // Called when a previously created loader has finished loading    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {        // Swap the new cursor in.  (The framework will take care of closing the        // old cursor once we return.)        mAdapter.swapCursor(data);    }    // Called when a previously created loader is reset, making the data unavailable    public void onLoaderReset(Loader<Cursor> loader) {        // This is called when the last Cursor provided to onLoadFinished()        // above is about to be closed.  We need to make sure we are no        // longer using it.        mAdapter.swapCursor(null);    }    @Override     public void onListItemClick(ListView l, View v, int position, long id) {        // Do something when a list item is clicked    }}  

5.ListView动态获取网络数据方式【见下一节文章】

6.ExpandableListView相关类和知识点

   public class  ExpandableListView extends ListView:ListView的子类,android.widget.ExpandableListView
   两级列表,分为组和组中Items,使用ExpandableListAdapter接口提供数据;

   重要的接口:
   ExpandableListView.OnChildClickListener 、ExpandableListView.OnGroupClickListener
   ExpandableListView.OnGroupCollapseListener 、ExpandableListView.OnGroupExpandListener


   重要的XML属性:
   android:childDivider:color或者Drawable资源文件,子项目的分隔符
   android:childIndicator :状态列表的Drawable资源文件,用于定义子项目各种状态对应的效果
   android:groupIndicator 


   重要方法:
   ExpandableListAdapter getExpandableListAdapter():
   boolean collapseGroup(int groupPos)
   boolean expandGroup(int groupPos)
   boolean expandGroup(int groupPos, boolean animate)
   long getSelectedPosition():获取选择Group或者child的位置,该位置是打包以后的;综合的
   long getSelectedId ():获取已经选择的Group或者child的id,如果没选择,则返回-1;
   static int getPackedPositionChild(long packedPosition)  
   public boolean setSelectedChild (int groupPosition, int childPosition, boolean shouldExpandGroup)
   public void setSelectedGroup (int groupPosition)

   相关的类public interface ExpandableListAdapter:按Group组织数据,为可展开类别提供数据;
   间接子类:
   BaseExpandableListAdapter, CursorTreeAdapter, ResourceCursorTreeAdapter, 
   SimpleCursorTreeAdapter, SimpleExpandableListAdapter
   
   SimpleExpandableListAdapter:

   注意groupTo和ChildTo所对应的视图都是TextView才行(ImageView不行,其它类型的视图,需要重写getGroupView和getChildView方法;);
       简单的Adapter映射静态数据到group和child view。
       构造器:9个参数

       SimpleExpandableListAdapter(Context context, List<? extends Map<String, ?>> groupData, int groupLayout,                 String[] groupFrom, int[] groupTo, List<? extends List<? extends Map<String, ?>>> childData,                 int childLayout, String[] childFrom, int[] childTo)
                 context:AdapterView运行环境上下文
                 groupData:Map的列表,列表中的每一项代表一组所有属性数据,Map包含组的数据,至少包含groupFrom所有的条目,例如每个Group需要一个textView和ImageView,那么可以map1.put("text","xxxx"); map1.put("image", "ddd")作为第一组的group Item;
                 groupLayout:Group视图的布局文件id,至少包含groupTo中的所有组件id
                 groupFrom:一组keys(用于获取每个组的数据,因为一个组项view可能需要多个数据),用于从Maps获取关联的该组view的数据
                 groupTo:一组view id,用于对应展示groupFrom中列数据
                 childData:Map对象列表的列表,外围的列表代表每个组,里面的列表代表每一组里面的项所有属性数据;

 其它参数类似;   

       SimpleExpandableListAdapter(Context context, List<? extends Map<String, ?>> groupData,                 int expandedGroupLayout, int collapsedGroupLayout, String[] groupFrom,                int[] groupTo, List<? extends List<? extends Map<String, ?>>> childData,                 int childLayout, String[] childFrom, int[] childTo)       SimpleExpandableListAdapter(Context context, List<? extends Map<String, ?>> groupData,                int expandedGroupLayout, int collapsedGroupLayout, String[] groupFrom, int[] groupTo,                 List<? extends List<? extends Map<String, ?>>> childData, int childLayout,                 int lastChildLayout, String[] childFrom, int[] childTo)

        SimpleCursorTreeAdapter:
        
SimpleCursorTreeAdapter(Context context, Cursor cursor, int collapsedGroupLayout,                 int expandedGroupLayout, String[] groupFrom, int[] groupTo, int childLayout,                  int lastChildLayout, String[] childFrom, int[] childTo)        SimpleCursorTreeAdapter(Context context, Cursor cursor, int collapsedGroupLayout,                 int expandedGroupLayout, String[] groupFrom, int[] groupTo, int childLayout,                 String[] childFrom, int[] childTo)        SimpleCursorTreeAdapter(Context context, Cursor cursor, int groupLayout, String[] groupFrom,                 int[] groupTo, int childLayout, String[] childFrom, int[] childTo)

7.ExpandableListView的使用实例

    参见上篇文章:http://blog.csdn.net/meplusplus/article/details/26622261

8.如何定制自己的ExpandableListAdapter

     主要是学习系统的源码实现,继承已有的ListAdapter,以下是系统SimpleExpandableListAdapter的源码实现,我们可以继承然后重写getChildView和getGroupView方法;
package android.widget;import android.content.Context;import android.view.View;import android.view.ViewGroup;import android.view.LayoutInflater;import java.util.List;import java.util.Map;/** * An easy adapter to map static data to group and child views defined in an XML * file. You can separately specify the data backing the group as a List of * Maps. Each entry in the ArrayList corresponds to one group in the expandable * list. The Maps contain the data for each row. You also specify an XML file * that defines the views used to display a group, and a mapping from keys in * the Map to specific views. This process is similar for a child, except it is * one-level deeper so the data backing is specified as a List<List<Map>>, * where the first List corresponds to the group of the child, the second List * corresponds to the position of the child within the group, and finally the * Map holds the data for that particular child. */public class SimpleExpandableListAdapter extends BaseExpandableListAdapter {    private List<? extends Map<String, ?>> mGroupData;    private int mExpandedGroupLayout;    private int mCollapsedGroupLayout;    private String[] mGroupFrom;    private int[] mGroupTo;        private List<? extends List<? extends Map<String, ?>>> mChildData;    private int mChildLayout;    private int mLastChildLayout;    private String[] mChildFrom;    private int[] mChildTo;        private LayoutInflater mInflater;        /**     * Constructor     *      * @param context The context where the {@link ExpandableListView}     *            associated with this {@link SimpleExpandableListAdapter} is     *            running     * @param groupData A List of Maps. Each entry in the List corresponds to     *            one group in the list. The Maps contain the data for each     *            group, and should include all the entries specified in     *            "groupFrom"     * @param groupFrom A list of keys that will be fetched from the Map     *            associated with each group.     * @param groupTo The group views that should display column in the     *            "groupFrom" parameter. These should all be TextViews. The     *            first N views in this list are given the values of the first N     *            columns in the groupFrom parameter.     * @param groupLayout resource identifier of a view layout that defines the     *            views for a group. The layout file should include at least     *            those named views defined in "groupTo"     * @param childData A List of List of Maps. Each entry in the outer List     *            corresponds to a group (index by group position), each entry     *            in the inner List corresponds to a child within the group     *            (index by child position), and the Map corresponds to the data     *            for a child (index by values in the childFrom array). The Map     *            contains the data for each child, and should include all the     *            entries specified in "childFrom"     * @param childFrom A list of keys that will be fetched from the Map     *            associated with each child.     * @param childTo The child views that should display column in the     *            "childFrom" parameter. These should all be TextViews. The     *            first N views in this list are given the values of the first N     *            columns in the childFrom parameter.     * @param childLayout resource identifier of a view layout that defines the     *            views for a child. The layout file should include at least     *            those named views defined in "childTo"     */    public SimpleExpandableListAdapter(Context context,            List<? extends Map<String, ?>> groupData, int groupLayout,            String[] groupFrom, int[] groupTo,            List<? extends List<? extends Map<String, ?>>> childData,            int childLayout, String[] childFrom, int[] childTo) {        this(context, groupData, groupLayout, groupLayout, groupFrom, groupTo, childData,                childLayout, childLayout, childFrom, childTo);    }    /**     * Constructor     *      * @param context The context where the {@link ExpandableListView}     *            associated with this {@link SimpleExpandableListAdapter} is     *            running     * @param groupData A List of Maps. Each entry in the List corresponds to     *            one group in the list. The Maps contain the data for each     *            group, and should include all the entries specified in     *            "groupFrom"     * @param groupFrom A list of keys that will be fetched from the Map     *            associated with each group.     * @param groupTo The group views that should display column in the     *            "groupFrom" parameter. These should all be TextViews. The     *            first N views in this list are given the values of the first N     *            columns in the groupFrom parameter.     * @param expandedGroupLayout resource identifier of a view layout that     *            defines the views for an expanded group. The layout file     *            should include at least those named views defined in "groupTo"     * @param collapsedGroupLayout resource identifier of a view layout that     *            defines the views for a collapsed group. The layout file     *            should include at least those named views defined in "groupTo"     * @param childData A List of List of Maps. Each entry in the outer List     *            corresponds to a group (index by group position), each entry     *            in the inner List corresponds to a child within the group     *            (index by child position), and the Map corresponds to the data     *            for a child (index by values in the childFrom array). The Map     *            contains the data for each child, and should include all the     *            entries specified in "childFrom"     * @param childFrom A list of keys that will be fetched from the Map     *            associated with each child.     * @param childTo The child views that should display column in the     *            "childFrom" parameter. These should all be TextViews. The     *            first N views in this list are given the values of the first N     *            columns in the childFrom parameter.     * @param childLayout resource identifier of a view layout that defines the     *            views for a child. The layout file should include at least     *            those named views defined in "childTo"     */    public SimpleExpandableListAdapter(Context context,            List<? extends Map<String, ?>> groupData, int expandedGroupLayout,            int collapsedGroupLayout, String[] groupFrom, int[] groupTo,            List<? extends List<? extends Map<String, ?>>> childData,            int childLayout, String[] childFrom, int[] childTo) {        this(context, groupData, expandedGroupLayout, collapsedGroupLayout,                groupFrom, groupTo, childData, childLayout, childLayout,                childFrom, childTo);    }    /**     * Constructor     *      * @param context The context where the {@link ExpandableListView}     *            associated with this {@link SimpleExpandableListAdapter} is     *            running     * @param groupData A List of Maps. Each entry in the List corresponds to     *            one group in the list. The Maps contain the data for each     *            group, and should include all the entries specified in     *            "groupFrom"     * @param groupFrom A list of keys that will be fetched from the Map     *            associated with each group.     * @param groupTo The group views that should display column in the     *            "groupFrom" parameter. These should all be TextViews. The     *            first N views in this list are given the values of the first N     *            columns in the groupFrom parameter.     * @param expandedGroupLayout resource identifier of a view layout that     *            defines the views for an expanded group. The layout file     *            should include at least those named views defined in "groupTo"     * @param collapsedGroupLayout resource identifier of a view layout that     *            defines the views for a collapsed group. The layout file     *            should include at least those named views defined in "groupTo"     * @param childData A List of List of Maps. Each entry in the outer List     *            corresponds to a group (index by group position), each entry     *            in the inner List corresponds to a child within the group     *            (index by child position), and the Map corresponds to the data     *            for a child (index by values in the childFrom array). The Map     *            contains the data for each child, and should include all the     *            entries specified in "childFrom"     * @param childFrom A list of keys that will be fetched from the Map     *            associated with each child.     * @param childTo The child views that should display column in the     *            "childFrom" parameter. These should all be TextViews. The     *            first N views in this list are given the values of the first N     *            columns in the childFrom parameter.     * @param childLayout resource identifier of a view layout that defines the     *            views for a child (unless it is the last child within a group,     *            in which case the lastChildLayout is used). The layout file     *            should include at least those named views defined in "childTo"     * @param lastChildLayout resource identifier of a view layout that defines     *            the views for the last child within each group. The layout     *            file should include at least those named views defined in     *            "childTo"     */    public SimpleExpandableListAdapter(Context context,            List<? extends Map<String, ?>> groupData, int expandedGroupLayout,            int collapsedGroupLayout, String[] groupFrom, int[] groupTo,            List<? extends List<? extends Map<String, ?>>> childData,            int childLayout, int lastChildLayout, String[] childFrom,            int[] childTo) {        mGroupData = groupData;        mExpandedGroupLayout = expandedGroupLayout;        mCollapsedGroupLayout = collapsedGroupLayout;        mGroupFrom = groupFrom;        mGroupTo = groupTo;                mChildData = childData;        mChildLayout = childLayout;        mLastChildLayout = lastChildLayout;        mChildFrom = childFrom;        mChildTo = childTo;                mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);    }        public Object getChild(int groupPosition, int childPosition) {        return mChildData.get(groupPosition).get(childPosition);    }    public long getChildId(int groupPosition, int childPosition) {        return childPosition;    }    public View getChildView(int groupPosition, int childPosition, boolean isLastChild,            View convertView, ViewGroup parent) {        View v;        if (convertView == null) {            v = newChildView(isLastChild, parent);        } else {            v = convertView;        }        bindView(v, mChildData.get(groupPosition).get(childPosition), mChildFrom, mChildTo);        return v;    }    /**     * Instantiates a new View for a child.     * @param isLastChild Whether the child is the last child within its group.     * @param parent The eventual parent of this new View.     * @return A new child View     */    public View newChildView(boolean isLastChild, ViewGroup parent) {        return mInflater.inflate((isLastChild) ? mLastChildLayout : mChildLayout, parent, false);    }        private void bindView(View view, Map<String, ?> data, String[] from, int[] to) {        int len = to.length;        for (int i = 0; i < len; i++) {            TextView v = (TextView)view.findViewById(to[i]);            if (v != null) {                v.setText((String)data.get(from[i]));            }        }    }    public int getChildrenCount(int groupPosition) {        return mChildData.get(groupPosition).size();    }    public Object getGroup(int groupPosition) {        return mGroupData.get(groupPosition);    }    public int getGroupCount() {        return mGroupData.size();    }    public long getGroupId(int groupPosition) {        return groupPosition;    }    public View getGroupView(int groupPosition, boolean isExpanded, View convertView,            ViewGroup parent) {        View v;        if (convertView == null) {            v = newGroupView(isExpanded, parent);        } else {            v = convertView;        }        bindView(v, mGroupData.get(groupPosition), mGroupFrom, mGroupTo);        return v;    }    /**     * Instantiates a new View for a group.     * @param isExpanded Whether the group is currently expanded.     * @param parent The eventual parent of this new View.     * @return A new group View     */    public View newGroupView(boolean isExpanded, ViewGroup parent) {        return mInflater.inflate((isExpanded) ? mExpandedGroupLayout : mCollapsedGroupLayout,                parent, false);    }    public boolean isChildSelectable(int groupPosition, int childPosition) {        return true;    }    public boolean hasStableIds() {        return true;    }}

转载请附上本页链接:来自CSDN博客——MePlusPlus(Me++)的专栏 (http://blog.csdn.net/meplusplus)
欢迎留言交流。


0 0
原创粉丝点击