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()方法;
定制每一项文本内容,可以重写数组中每个对象的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.youkuaiyun.com/meplusplus/article/details/26622261
8.如何定制自己的ExpandableListAdapter
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;
}
}