【重拾Android】详谈BaseApapter类的使用,并结合ListView进行说明



BaseAdapter需要重写的方法:
getCount(),getItem(int position),getItemId(int position),getView(int position, View convertView, ViewGroup parent)

listView在开始绘制的时候,系统首先调用getCount()函数,根据他的返回值得到 listView的长度,然后根据这个长度,调用getView()逐一绘制每一行。如果你的 getCount()返回值是0的话,列表将不显示同样return 1,就只显示一行。系统显示列表时,首先实例化一个适配器(这里将实例化自定义的适配器)。当手动完成适配时,必须手动映射数据,这需要重写getView()方 法。系统在绘制列表的每一行的时候将调用此方法。getView()有三个参数,position表示将显示的是第几行,covertView是从布局文 件中inflate来的布局。我们用LayoutInflater的方法将定义好的item.xml文件提取成View实例用来显示。然后将xml文件中 的各个组件实例化(简单的findViewById()方法)。这样便可以将数据对应到各个组件上了。但是按钮为了响应点击事件,需要为它添加点击监听 器,这样就能捕获点击事件。至此一个自定义的listView就完成了,现在让我们回过头从新审视这个过程。系统要绘制ListView了,他首先获得要 绘制的这个列表的长度,然后开始绘制第一行,怎么绘制呢?调用getView()函数。在这个函数里面首先获得一个View(实际上是一个 ViewGroup),然后再实例并设置各个组件,显示之。好了,绘制完这一行了。那再绘制下一行,直到绘完为止。

BaseAdapter中若需要动态的修改Item中显示的内容,则组要先修改 getView()中的绘制数据,
在下面例子中是ps,然后再调用Adapter中的 notifyDataSetChanged()方法进行重绘即可。

public class MyListViewAdapter extends BaseAdapter {

 private Context context;
 private LayoutInflater factory;
 
 //该类就是数据类
 private List<Person> ps;

 public MyListViewAdapter(Context context,List<Person> ps) {

  this.context = context;
  this.factory = LayoutInflater.from(context);
  this.ps = ps;

 }

 //数据重置
 public void resetData(List<Person> ps) {
  this.ps = ps;
 }

 //获取数据
 public List<Person> getData() {
  return ps;
 }
 
 @Override
 public int getCount() {
  return ps.size();
 }

 @Override
 public Object getItem(int position) {
  return position;
 }

 @Override
 public long getItemId(int position) {
  return position;
 }

 //重要方法
 @Override
 public View getView(final int position, View convertView, ViewGroup parent) {

  ListItemViewHolder listItemViewHolder = null;
  //convertView为null的时候初始化convertView。
  if (convertView == null) {

   listItemViewHolder = new ListItemViewHolder();
   convertView = factory.inflate(R.layout.listitem_maininfo, null);
   listItemViewHolder.title = (TextView)convertView.findViewById(R.id.tv_listitem_name);
   listItemViewHolder.detail = (TextView)convertView.findViewById(R.id.tv_listitem_detail);
   listItemViewHolder.delet = (Button)convertView.findViewById(R.id.btn_listitem_delet);
   //这里很重要,不然无法找回数据
   convertView.setTag(listItemViewHolder);

  } else {
   listItemViewHolder = (ListItemViewHolder)convertView.getTag();
  }

  //为每个控件初始化信息
  listItemViewHolder.title.setText(ps.get(position).getName());
  listItemViewHolder.detail.setText(ps.get(position).getBirsthday());
  listItemViewHolder.delet.setOnClickListener(new OnClickListener(){
   
   @Override
   public void onClick(View v){

    new AlertDialog.Builder(context).setTitle("确认删除吗?")
    .setPositiveButton("确定", new DialogInterface.OnClickListener() {

     @Override
     public void onClick(DialogInterface dialog, int which) {
      // 点击“确认”后的操作
      PersonService personService = new PersonService(context);
      personService.delete(ps.get(position));
      ps.remove(position);
      MyListViewAdapter.this.notifyDataSetChanged();
     }
    })
    .setNegativeButton("取消", new DialogInterface.OnClickListener() {

     @Override
     public void onClick(DialogInterface dialog, int which) {

     }
    }).show();
   }
  });
  return convertView;
 }
 
 //ViewHoider可以以内部类的形式写在里面以使代码更加简洁
 public class ListItemViewHolder {
       
  public TextView title;
  public TextView detail;
  public Button delet;

 }
}


另外再介绍一下Button等控件放在Listview等的item中时, Listview_ item如何获取点击事件
简单来说,就是

在item的

< RelativeLayout>中

android:descendantFocusability= "blocksDescendants"

<Button>中

android:focusable = "false"


这是开发中很常见的一个问题,项目中的listview不仅仅是简单的文字,常常需要自己定义listview,自己的Adapter去继承BaseAdapter,在adapter中按照需求进行编写,问题就出现了,可能会发生点击每一个item的时候没有反应,无法获取的焦点。原因多半是由于在你自己定义的Item中存在诸如ImageButton,Button,CheckBox等子控件(也可以说是Button或者Checkable的子类控件),此时这些子控件会将焦点获取到,所以常常当点击item时变化的是子控件,item本身的点击没有响应。

    

这时候就可以使用descendantFocusability来解决啦,API描述如下:

android:descendantFocusability

Defines the relationship between the ViewGroup and its descendants when looking for a View to take focus.

Must be one of the following constant values.

 

该属性是当一个为view获取焦点时,定义viewGroup和其子控件两者之间的关系。

属性的值有三种:

        

        beforeDescendants:viewgroup会优先其子类控件而获取到焦点

        afterDescendants:viewgroup只有当其子类控件不需要获取焦点时才获取焦点

        blocksDescendants:viewgroup会覆盖子类控件而直接获得焦点

 

通常我们用到的是第三种,即在Item布局的根布局加上android:descendantFocusability=”blocksDescendants”的属性就好了。



另外开发中还遇到一个问题,listview的getView()方法会莫名其妙的执行3次,原来是listview的布局文件的问题: 

<ListView android:id="@+id/list"

android:layout_width="fill_parent"

android:layout_height="wrap_content" />

将android:layout_height="wrap_content"修改成:android:layout_height="fill_parent"就可以了。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值