Android Adapter 与 Listview
一、Adapter,BaseAdapter
BaseAdapter应用程序中经常用到的基础数据适配器,它的主要用途是将一组数据传到像ListView、Spinner、Gallery及GridView等UI显示组件,它是继承自接口类Adapter,Adapter有如下结构:
Public Methods | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
abstract int | getCount()
How many items are in the data set represented by this Adapter.
|
||||||||||
abstract Object | getItem(int position)
Get the data item associated with the specified position in the data set.
|
||||||||||
abstract long | getItemId(int position)
Get the row id associated with the specified position in the list.
|
||||||||||
abstract int | getItemViewType(int position)
Get the type of View that will be created by
getView(int, View, ViewGroup) for the specified item. |
||||||||||
abstract View | getView(int position, View convertView, ViewGroup parent)
Get a View that displays the data at the specified position in the data set.
|
||||||||||
abstract int | getViewTypeCount()
Returns the number of types of Views that will be created by |
||||||||||
abstract boolean | hasStableIds()
Indicates whether the item ids are stable across changes to the underlying data.
|
||||||||||
abstract boolean | isEmpty() | ||||||||||
abstract void | registerDataSetObserver(DataSetObserver observer)
Register an observer that is called when changes happen to the data used by this adapter.
|
||||||||||
abstract void | unregisterDataSetObserver(DataSetObserver observer)
Unregister an observer that has previously been registered with this adapter via
registerDataSetObserver(DataSetObserver) . |
BaseAdapter用的最多,BaseAdapter实现了ListAdapter和SpinnerAdapter两个接口,当然它也可以直接给ListView和Spinner等UI组件直接提供数据。使用BaseAdapter必须写一个类继承它,同时BaseAdapter是一个抽象类,继承它必须实现它的方法。BaseAdapter的灵活性就在于它要重写很多方法,其中最重要的即为getView()方法,当系统开始绘制ListView的时候,首先调用getCount()方法。得到它的返回值,即ListView的长度。然后系统调用getView()方法,根据这个长度逐一绘制ListView的每一行。也就是说,如果让getCount()返回1,那么只显示一行。而getItem()和getItemId()则在需要处理和取得Adapter中的数据时调用。查阅关于getView方法的api手册如下:
public abstract View getView(int position, View convertView, ViewGroup parent)
Get a View that displays the data at the specified position in the data set. You can either create a View manually or inflate it from an XML layout file. When the View is inflated, the parent View (GridView, ListView...) will apply default layout parameters unless you use inflate(int, android.view.ViewGroup, boolean)
to specify a root view and to prevent attachment to the root.
Parameters:
position
The position of the item within the adapter's data set of the item whose view we want.
convertView
The old view to reuse, if possible. Note: You should check that this view is non-null and of an appropriate type before using. If it is not possible to convert this view to display the correct data, this method can create a new view. Heterogeneous lists can specify their number of view types, so that this View is always of the right type (see getViewTypeCount() and getItemViewType(int)).
parent
The parent that this view will eventually be attached to
Returns
A View corresponding to the data at the specified position.
二、使用自定义Adapter承载的ListView
常用的Adapter:BaseAdapter,ArrayAdapter,SimpleAdapter和SimpleCursorAdapter,ArrayAdapter最为简单,只能展示一行字。SimpleAdapter有最好的扩充性,可以自定义出各种效果。 BaseAdapter自由度更高,SimpleAdpater 是BaseAdapter的子类之一。SimpleCursorAdapter可以认为是SimpleAdapter对数据库的简单结合,可以方面的把数据库的内容以列表的形式展示出来。这里两个Demo分别使用SimpleAdapter和BaseAdapter来实现两种功能自由度比较高的ListView。
1,SimpleAdapter Demo
构建一个显示图片和文字的ListView,捕获点击和长按的操作。
ListItem的XML实现,data.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout android:id="@+id/RelativeLayout01" android:layout_width="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android" android:layout_height="wrap_content" android:paddingBottom="4dip" android:paddingLeft="12dip" android:paddingRight="12dip"> <ImageView android:paddingTop="12dip" android:layout_alignParentRight="true" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/ItemImage" /> <TextView android:text="TextView01" android:layout_height="wrap_content" android:textSize="20dip" android:layout_width="fill_parent" android:id="@+id/ItemTitle" /> <TextView android:text="TextView02" android:layout_height="wrap_content" android:layout_width="fill_parent" android:layout_below="@+id/ItemTitle" android:id="@+id/ItemText" /> </RelativeLayout>
/layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout android:id="@+id/LinearLayout01" android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android"> <ListView android:id="@+id/ListView01" android:layout_width="wrap_content" android:layout_height="wrap_content" > </ListView> </LinearLayout>
MainActivity.java
捕获点击和长按的操作,并且在menu里面加入点击导航到另外一个Baseadapter demo里面
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //绑定Layout里面的ListView ListView list = (ListView) findViewById(R.id.ListView01); //生成动态数组,加入数据 ArrayList<HashMap<String, Object>> listItem = new ArrayList<HashMap<String, Object>>(); for(int i=0;i<20;i++) { HashMap<String, Object> map = new HashMap<String, Object>(); map.put("ItemImage", R.drawable.ic_launcher);//图像资源的ID map.put("ItemTitle", "Title"+i); map.put("ItemText", "the info of this Item!"); listItem.add(map); } //生成适配器的Item和动态数组对应的元素 SimpleAdapter listItemAdapter = new SimpleAdapter(this,listItem,//数据源 R.layout.data,//ListItem的XML实现 //动态数组与ImageItem对应的子项 new String[] {"ItemImage","ItemTitle", "ItemText"}, //ImageItem的XML文件里面的一个ImageView,两个TextView ID new int[] {R.id.ItemImage,R.id.ItemTitle,R.id.ItemText} ); //添加并且显示 list.setAdapter(listItemAdapter); //添加点击 list.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { // TODO Auto-generated method stub setTitle("点击第"+arg2+"个项目"); } }); //添加长按点击 list.setOnCreateContextMenuListener(new OnCreateContextMenuListener() { @Override public void onCreateContextMenu(ContextMenu arg0, View arg1, ContextMenuInfo arg2) { // TODO Auto-generated method stub arg0.setHeaderTitle("长按菜单-ContextMenu"); arg0.add(0, 0, 0, "弹出长按菜单0"); arg0.add(0, 1, 0, "弹出长按菜单1"); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); MenuItem menuItem= menu.getItem(0); menuItem.setTitle("自定义ListView"); menuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() { public boolean onMenuItemClick(MenuItem item) { // TODO Auto-generated method stub Intent intent=new Intent(); intent.setClass(MainActivity.this, SecondActivity.class); MainActivity.this.startActivity(intent); return false; } }); return true; } //长按菜单响应函数 @Override public boolean onContextItemSelected(MenuItem item) { setTitle("点击了长按菜单里面的第"+item.getItemId()+"个项目"); return super.onContextItemSelected(item); } }
2,BaseAdapter demo
实现带Checkbox的ListView
ListItem的XML实现,m_data.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal" > <ImageView android:id="@+id/img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical"/> <TextView android:id="@+id/title" android:textSize="18dip" android:layout_weight="1" android:textStyle="bold" android:gravity="center_horizontal|center_vertical" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <CheckBox android:id="@+id/cb" android:layout_width="wrap_content" android:layout_height="wrap_content" android:focusable="false" android:focusableInTouchMode="false" android:clickable="false" android:checkMark="?android:attr/listChoiceIndicatorMultiple"/> </LinearLayout>
/layout/second_activity.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <ListView android:id="@+id/lv" android:layout_width="fill_parent" android:layout_height="wrap_content"/> </LinearLayout>
MyListViewAdapter.java
自定义Adapter MyListViewAdapter
public class MyListViewAdapter extends BaseAdapter{ private LayoutInflater mInflater; private List<Map<String, Object>> mData; public static Map<Integer, Boolean> isSelected; //记录checkbox状态的 String [] string ={"Title"}; int [] img ={R.drawable.ic_launcher}; public MyListViewAdapter(Context context ){ mInflater = LayoutInflater.from(context); init(); } private void init() { // TODO Auto-generated method stub mData=new ArrayList<Map<String, Object>>(); for(int i=0;i<100;i++){ Map<String,Object> map=new HashMap<String, Object>(); map.put("img",img[0]); map.put("title",string[0] ); mData.add(map); } //这儿定义isSelected这个map是记录每个listitem的状态,初始状态全部为false。 isSelected = new HashMap<Integer, Boolean>(); for(int i=0;i<mData.size();i++){ isSelected.put(i, false); } } public int getCount(){ return mData.size(); } public Object getItem(int position){ return null; } public long getItemId(int position){ return 0; } public View getView(int position,View convertView,ViewGroup parent) { ViewHolder holder = null;// if(convertView==null){ holder=new ViewHolder(); convertView = mInflater.inflate(R.layout.m_data, null); holder.img = (ImageView) convertView.findViewById(R.id.img); holder.title = (TextView) convertView.findViewById(R.id.title); holder.cBox = (CheckBox) convertView.findViewById(R.id.cb); convertView.setTag(holder); }else { holder = (ViewHolder) convertView.getTag(); } holder.img.setBackgroundResource((Integer) mData.get(position).get( "img")); holder.title.setText(mData.get(position).get("title").toString()); holder.cBox.setChecked(isSelected.get(position)); return convertView; } }
临时存储器ViewHoder类
public final class ViewHolder { public ImageView img; public TextView title; public CheckBox cBox; }
从MainActivity跳转到的第二个Activity:SecondActivity.java
public class SecondActivity extends Activity { private ListView listview; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.second_activity); listview =(ListView)findViewById(R.id.lv); MyListViewAdapter myListViewAdapter=new MyListViewAdapter(this); listview.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); listview.setItemsCanFocus(false); listview.setAdapter((ListAdapter) myListViewAdapter); listview.setOnItemClickListener(clickListener); listview.getCheckedItemPositions(); } private OnItemClickListener clickListener=new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position,long id){ ViewHolder vHollder = (ViewHolder) view.getTag(); //在每次获取点击的item时将对于的checkbox状态改变,同时修改map的值。 vHollder.cBox.toggle(); MyListViewAdapter.isSelected.put(position, vHollder.cBox.isChecked()); } }; }
效果图:
demo的java包均没有包含,需要根据提示自行导入。
刚接触android编程,发现java和C#如此相近,eclipse也用起来很顺手。