Android自学——ListView

ListView

​ 简介:ListView允许用户通过手指上下滑动的方式将屏幕外的数据滚动到屏幕内,例如QQ的聊天记录等。所谓ListView也就是把具有相同布局的View给放在一个列表中展示而已

​ 使用ListView需要设置数据适配器Adapter,那什么是Adapter?

Adapter

An Adapter object acts as a bridge between an AdapterView and the underlying data for that view. The Adapter provides access to the data items. The Adapter is also responsible for making a View for each item in the data set.

一个Adapter是AdapterView视图与数据之间的桥梁,Adapter提供对数据的访问,也负责为每一项数据产生一个对应的View,后将View添加到ListView之中。

​ 可能直接这样说比较抽象,下面我们来举例说明一下:我们的手机通讯录就是一个简单的ListView。通讯录中有一条一条的联系人,每一个联系人都显示了相应的信息。现在通讯录比较简单,一般情况下只显示头像和姓名,以前还会显示手机号。每一条联系人的显示方式又是一个View。Adapter适配器将我们的信息(头像和姓名)根据一定的格式适配到每个View中,然后再将View添加到ListView中。大家根据这个例子可能对ListView控件和Adapter适配器以及他们之间的关系有了更好的理解了。

引用自http://www.cnblogs.com/gaobig/p/5016651.html

​ Adapter的构造函数有三个参数,分别代表当前上下文ListView子项布局的id要适配的数据

​ Android提供了很多适配器的实现类,我们这里先看看ArrayAdapter,其通过泛型来指定要适配的数据,比如我们要传入文本类型的数据:

private String[] data = {"a", "b", "c", "d", "e", "f", "g"};

@Override
protected void onCreate(Bindle savedInstanceState) {
  super.onCreate(saveInstanceState);
  setContentView(R.id.activity_main);
  //生成适配器实例,其中android.R.layout.simple_list_item_1是内置的简单布局,只含有一个TextView
  ArrayAdapter<String> adapter = new ArrayAdapter<String>(MainActivity.this,
                                    android.R.layout.simple_list_item_1, data);
  //生成ListView实例并载入适配器,
  //其中R.id.lsit_view是自定义的ListView控件,该控件的用法和普通控件一样,这里就不写布局的代码了
  ListView listView = (ListView) findViewById(R.id.lsit_view);
  listView.setAdapter(adapter);
}

​ Adapter中有一个getView()方法,每当子项被滚动到屏幕内的时候就会被ListView调用,用于干什么呢?当然是给当前的ListView的子项填进一个View,所以理所当然该方法返回的是View类型,因此如果要自定义ListView的子项布局的话,就可以自己新建一个View然后再用自定义的布局的控件跟View绑定到一起。

​ 那怎么绑定呢?我们看一下下面的例子:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
  View view = LayoutInflater.from(getContext()).inflate(自定义子项布局的id, parent, false);
  //对View中的控件进行设置,如:
  TextView text = (TextView) view.findViewById(R.id.text);
  text.setText("Hello");
  return view;
}

​ 这里有必要再解释一下LayoutInflater.from(getContext()).inflate()

LayoutInflater.from(getContext())可以构造出一个LayoutInflater对象,然后调用inflate()方法动态加载一个布局。inflate()方法有三个参数,,第一个参数是要填充的布局的id,第二个是父布局,第三个是是否把布局先添加到父布局再返回View。其中第三个参数省略的话默认为true:

inflate()方法第三个参数attachToRoot是true的话,那第一个参数的layout文件就会被填充并附加在第二个参数所指定的ViewGroup内。方法返回结合后的View,根元素是第二个参数ViewGroup。如果是false的话,第一个参数所指定的layout文件会被填充并作为View返回。这个View的根元素就是layout文件的根元素。不管是true还是false,都需要ViewGroup的LayoutParams来正确的测量与放置layout文件所产生的View对象。

作者:斯科特安链接:http://www.jianshu.com/p/41796f541e67來源:简书 著作权归作者所有。

​ 反正就是这样来给View加载布局的。

​ 然后就是要说说怎么自定义Adapter了,比如我们要在ListView中展示水果图片+名字的一组列表:

/*在定义Adapter之前先定义一个我们要展示的数据的类*/

public class Fruit {

  private String name;
  private int imageId;

  public Fruit(String name, int imagId) {
    this.name = name;
    this.imageId = imageId;
  }

  //此处省略两个成员变量的getter和setter方法
  ...
}
/*一般自定义Adapter可以选择继承ArrayAdapter,可以省下很多功夫*/

public class FruitAdapter extends ArrayAdapter<Fruit> {

  //resourceId是我们自定义的布局的id,在后面的getView()方法中需要用来给View加载布局
  private int resourceId;

  //第二个参数之所以叫textViewResourceId是因为我们继承的ArrayAdapter就是只用来展示TextView的
  //我们自定义的时候就可以传入我们自定义的布局id
  public FruitAdapter(Context context, int textViewResourceId, List<Fruit> objects) {
    super(context, textViewResourceId, objects);
    resourceId = textViewResourceId;
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
    View view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
    //对View中的控件进行设置
    TextView fruitName = (TextView) view.findViewById(R.id.name);
    ImagView fruitImage = (ImageView) view.findViewById(R.id.image)
    //getItem()方法是继承的ArrayAdapter中实现的方法,用于获取当前项的数据的实例
    Fruit fruit = getItem(position);
    fruitName.setText(fruit.getName());
    fruitImage.setImageResource(fruit.getImageId);
    return view;
  }
}

​ 自定义Adapter就是这样子了,应该没什么问题吧, 使用的话就跟ArrayAdapter的用法类似就可以了。

下面来学习怎么优化ListView的性能。

​ 首先由于每次子项进入怕屏幕的时候都会调用getView()方法,这样会导致每次都重新加载布局,当ListView快速滚动的时候性能就很差。

​ 仔细看Adapter的getView()方法,还会发现它的第二个参数convertView我们没有用到,这个参数就是用来缓存之前加载好的布局的。所以我们修改一下上面例子中getView()的内容:

@Override
  public View getView(int position, View convertView, ViewGroup parent) {
    View view;
    if (convertView == null) {
      view = = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
    } else {
      view = convertView;
    }
    ...
  }
}

​ 其次由于getView()方法中每次都会调用findViewById()来获取控件实例,因此我们可以借助一个ViewHolder来进行优化:

@Override
  public View getView(int position, View convertView, ViewGroup parent) {
    Fruit fruit = getItem(position);
    View view;
    ViewHolder viewHolder;
    if (convertView == null) {
      view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
      viewHolder = new ViewHolder();
      viewHolder.image = (ImageView) view.findViewById(R.id.iamge);
      viewHolder.name = (TextView) view.findViewById(R.id.name);
      //调用View的setTag()方法,该方法可以存储和View相关联的信息,然后调用View的getTag()可以读取信息
      view.setTag(viewHolder);
    } else {
      view = convertView;
      viewHolder = (ViewHolder) view.getTag();
    }
    viewHolder.name.setText(fruit.getName());
    viewHolder.image.setImageResource(fruit.getImageId());
    return view;
  }
}

class ViewHolder {
  ImageView image;
  TextView name;
}

​ 至此ListView的性能就很不错了。

ListView的每一个子项是可以点击的,下面学习一下如何注册点击事件。

ListView listView = (ListView) findViewById(R.id.list_View);
listView.setAdapter(adapter);
lsitView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
  @Override
  public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    Fruit fruit = fruitList.get(position);
    Toast.makeText(MainActivity.this, fruit.getName(), Toast.LENGTH_SHORT).show();
  }
});

​ 其实跟Button和TextView等的监听器差不多,过一下就可以了。

​ ListView的学习就到这里了,初次写博客,有啥错误欢迎批评指出。

主要参考文献:郭霖《第一行代码(第2版)》

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值