BaseAdapter
有时候,列表不光会用来做显示用,我们同样可以在在上面添加按钮。添加按钮首先要写一个有按钮的xml文件,然后自然会想到用上面的方法定义一个适配器,然后将数据映射到布局文件上。但是事实并非这样,因为按钮是无法映射的,即使你成功的用布局文件显示出了按钮(确实可以显示)也无法添加按钮的响应,这时就要研究一下ListView是如何现实的了,而且必须要重写一个类继承BaseAdapter。下面的示例将显示一个按钮和一个图片,两行字如果单击按钮将删除此按钮的所在行。并告诉你ListView究竟是如何工作的。
一。要达到的目的
如上图,在一个ListView 中加入各种数据 。且在点击 button 和 item 时都 有反应,这里,我们就要用到 BaseAdapter(如果用SimpleAdapter ,无法给Btn 加响应) ,并重写它的方法了。
首先是程序的整体架构。
(1)整体架构
与ListView (1)中的相同 ,我们用固定的架构 ,在这里,我们写入部分方法。
public class ListDemo extends Activity {
private String [] names; //原始 数据
private String [] infos ;
private int [] imgs;
private List<Map<String ,Object>>listItems ; //MyAdapter要用的数据格式
private ListView lv ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.listview);
loadData(); //将原始数据转化成MyAdapter 要的格式
initCtrl(); //完界面初始化与设置
lv.setOnItemClickListener(new OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id ) {
// TODO Auto-generated method stub
Toast.makeText(getBaseContext(),
"chat with "+names[position], Toast.LENGTH_SHORT).show();
Intent iChat= new Intent(getBaseContext() ,Chat.class);
startActivity(iChat);
}
});
}
private void initCtrl() {
// TODO Auto-generated method stub
lv =(ListView)findViewById(R.id.listView1);
MyAdapter adapter = new MyAdapter (getBaseContext() ,listItems);
lv.setAdapter(adapter);
}
private List<Map<String, Object>> loadData() {
// TODO Auto-generated method stub
names =new String []{"阿今 ","hwj","twq","isshe"};
imgs = new int [] {R.drawable.a1,R.drawable.b ,R.drawable.c, R.drawable.d};
infos =new String [] {"1988","1992","1993","1994"};
listItems =new ArrayList<Map<String,Object>> (); //实例化
for (int i=0;i<names.length;i++){
Map<String ,Object> map = new HashMap<String ,Object>();
map.put("name", names[i]);
map.put("info", infos[i]);
map.put("img", imgs[i]);
listItems.add(map);
}
return listItems;
}
}
重点与难点 在于 MyAdapter 的实现 。
(2) item 的XML 文件 item.xml
类似于这种布局,用相对布局最好实现 。注意,里面为了在加入 Button 后,Item 还能有响应,要取消Button 的焦点,我们用的是
android:focusable="false"
具体如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@+id/info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/name"
android:layout_below="@+id/name"
android:layout_marginTop="16dp"
android:text="info"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginLeft="20dp"
android:layout_toRightOf="@+id/img"
android:text="name"
android:textAppearance="?android:attr/textAppearanceLarge" />
<ImageView
android:id="@+id/img"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignBottom="@+id/info"
android:layout_alignParentLeft="true"
android:layout_marginLeft="15dp"
android:src="@drawable/a" />
<Button
android:id="@+id/btn"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/info"
android:layout_alignParentRight="true"
android:layout_marginRight="50dp"
android:focusable="false"
android:text="OK" />
</RelativeLayout>
(3) MyAdaper文件
重点在于重写 getView方法,注意,在构造函数 中一定要有context ,否则在后面要用到时没有办法 ,比如下面中的 Button 监听 器里面的。
下面程序 中,知识 点有: LayoutInflater 的用法,getTag()的用法 ,等。以后用的时候 可以参考 。
public class MyAdapter extends BaseAdapter {
private Context context;
private LayoutInflater inflater ;
private List<Map<String ,Object>>listItems;
private class ViewHolder{
ImageView img;
TextView name;
TextView info;
Button btn; //控件 的声明 都 在Holder里面
}
public MyAdapter(Context context, List<Map<String, Object>> listItems) {
// TODO Auto-generated constructor stub
this.listItems=listItems;
this.context=context;
inflater= LayoutInflater.from(context);
//新建 一个扩展布局,Obtains the LayoutInflater from the given context.
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return listItems.size() ;
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return listItems.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
System.out.println("getView " + position + " " + convertView);
ViewHolder holder;
/*
* Recycler(反复循环器):如果convertview 是第一次展示我们就创建新的Holder对象与之绑定,
* 并在最后通过return convertview 返回,去显示;如果convertview
* 是回收来的那么我们就不必创建新的holder对象,只需要把原来的绑定的holder取出加上新的数据就行了
*/
if (convertView ==null){
convertView= inflater.inflate(R.layout.item, null); //实例化要扩展的布局
holder= new ViewHolder();
holder.img= (ImageView) convertView.findViewById(R.id.img);
holder.name=(TextView) convertView.findViewById(R.id.name);
holder.info=(TextView) convertView.findViewById(R.id.info);
holder.btn= (Button)convertView.findViewById(R.id.btn);
convertView.setTag(holder);
/*Sets the tag associated with this view. A tag can be used to mark
* a view in its hierarchy and does not have to be unique within the hierarchy.
* Tags can also be used to store data within a view without resorting to
* another data structure.
*/
}else {
holder=(ViewHolder) convertView.getTag();
//将holder 添加到动态生成的View里面
}
//数据的设置
holder.name.setText((CharSequence) listItems.get(position).get("name"));
holder.info.setText((CharSequence) listItems.get(position).get("info"));
holder.img.setImageResource((Integer) listItems.get(position).get("img"));
holder.btn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Toast.makeText(context, "bnt clicked", Toast.LENGTH_SHORT).show();
}
});
return convertView;
}
}