第一行代码3.5-最常用和最难用的控件--ListView

  首先这个控件为什么是最常用的呢?因为手机屏幕大小有限,有些东西比如新闻、手机联系人微博等大量数据不可能全部显示出来,需要通过滑动手机屏幕翻阅信息。这种方法用到的控件就是ListView
1、ListView的简单用法
  首先创建一个工程名为ListViewTest,然后在activity_main.xml中添加如下代码:
这里写图片描述
  然后在MainActivity.java中添加:
这里写图片描述
  其中adapter的作用是设置ListView的布局和数据,第一个参数是context,第二个参数是Android自带的布局,第三个参数是数据。如果是微博,那么这个数据就来自网络,通讯录就来自本地。
  效果如下:

2、定制ListView的界面
  之前的界面太单调了,下面介绍怎么显示图片+文字。
  首先创建一个水果类,命名为Fruit:

package com.example.listviewtest;

public class Fruit {

    private String name; // 水果名
    private int imageId; // 水果图片id

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

    public String getName() {
        return name;
    }

    public int getImageId() {
        return imageId;
    }
}

  然后创建显示水果类的布局fruit_item.xml:左边水果图片,右边水果名

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    <ImageView android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/imageView"/>
    <TextView android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:id="@+id/textView"
        android:layout_marginLeft="10dp"/>

</LinearLayout>

  注意一些宽度和距离的设置。
  由于这个布局中显示的内容包括图片和文字,所以需要自定义适配器来显示:

public class FruitAdapter extends ArrayAdapter<Fruit>{

    private int resourceId;

    public FruitAdapter(Context context, int resource, List<Fruit> objects) {
        super(context, resource, objects);
        resourceId = resource;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        Fruit item = getItem(position);

        View view = LayoutInflater.from(getContext()).inflate(resourceId, null);
        TextView tv = (TextView) view.findViewById(R.id.textView);
        ImageView iv = (ImageView) view.findViewById(R.id.imageView);
        tv.setText(item.getName());
        iv.setImageResource(item.getImageId());

        return view;
    }

}

  其中getView函数在每一个子项被滚动到屏幕中显示的时候会被调用。在getView 方法中,首先通过getItem()方法得到当前项的Fruit 实例,然后使用LayoutInflater 来为这个子项加载我们传入的布局,接着调用View 的findViewById()方法分别获取到ImageView 和TextView 的实例,并分别调用它们的setImageResource()和setText()方法来设置显示的图片和文字,最后将布局返回,这样我们自定义的适配器就完成了。
  最后修改MainActivity的代码:
这里写图片描述
  这样水果的数据和界面都加载完成了。效果如下:
这里写图片描述

3、提升ListView运行效率
  之前说到ListView难用,原因之一就是有很多地方可以优化,其中一个地方就是修改getView函数:getView每次都会把布局重新加载一遍,所以当ListView快速滚动的时候,性能会产生瓶颈。
  getView中还有一个convertView参数,它就是之前加载的布局的缓存,所以可以这样得到view:

View view;
if (convertView == null) {
    view = LayoutInflater.from(getContext()).inflate(resourceId, null);
}
else view = convertView;

  这样在快速滚动ListView的时候效率会有所提升。但是还可以优化,因为每次还是要通过findViewById才能获取控件的实例,所以可以用一个ViewHolder来保存控件,如下:

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    final Fruit item = getItem(position);

    View view;
    ViewHolder viewHolder;
    if (convertView == null) {
        view = LayoutInflater.from(getContext()).inflate(resourceId, null);
        viewHolder = new ViewHolder();
        viewHolder.imageView = (ImageView) view.findViewById(R.id.imageView);
        viewHolder.textView = (TextView) view.findViewById(R.id.textView);
        view.setTag(viewHolder); // 将viewHolder存储到View中
    }
    else {
        view = convertView;
        viewHolder = (ViewHolder)view.getTag(); // 重新获取ViewHolder
    }
    viewHolder.textView.setText(item.getName());
    viewHolder.imageView.setImageResource(item.getImageId());

    return view;
}

  当view是新加载的时候,会把TextView和ImageView赋值给ViewHolder,并且附到View的TAG中,当读取缓存的时候再从View中获取回来。

4、ListView的点击事件
  如果ListView没有点击事件,那也是没什么作用的,所以需要设置每一项的点击事件。注意不是OnClickListener,而是OnItemClickListener。

listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {

    @Override
    public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
        Fruit fruit = fruitList.get(position);
        Toast.makeText(MainActivity.this, fruit.getName(), Toast.LENGTH_SHORT).show();
    }
});

  下面说说这四个参数是什么意思(来自20110921 onItemClick监听器四个arg参数):首先AdapterView表示你现在点击的ListView是哪个,通过View可以获取ListView里面某一项的内容(比如可以获取某一个水果的TextView或者ImageView),position表示点击的item在适配器里的位置,id表示点击的item是listview的第几行,在大部分情况下id和position是相同的。
  下面验证通过position获取的水果名和通过view获取的是一样的:

TextView fruitText = (TextView) view.findViewById(R.id.textView);
Toast.makeText(MainActivity.this, fruitText.getText().toString()+" "+fruit.getName(), Toast.LENGTH_SHORT).show(); // 输出两者相同

  下面是自己另外加的内容:设置长按删除点击事件。长按删除包括在list中删除对应水果和更新适配器。

listview.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {

    @Override
    public boolean onItemLongClick(AdapterView<?> adapterView, View view, int position, long id) {
        fruitList.remove(position); // 删除对应水果
        adapter = new FruitAdapter(MainActivity.this, R.layout.fruit_item, fruitList); // 更新适配器
        listview.setAdapter(adapter);
        return true;
    }
});
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值