第一行代码第二版ListView的使用(listView复用遇到的坑)

这个复杂又好用的控件,说不清是爱是恨。开始学习它吧。
首先当然是创建项目啊,然后修改一下activity_main的布局文件,内容如下

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ListView
        android:id="@+id/list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

这里就注意让它占满全屏就好了,按照之前控件的逻辑呢,现在只要去MainActiviry里边findViewById就行,这个不行,为啥?开头说了,它比较复杂嘛….这个控件呢需要一个适配器,,我们可以在适配器里面帮它绑定数据,方便它来展示
新建一个layout,,代码如下

<?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="wrap_content">

    <ImageView
        android:id="@+id/fruit_image"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:src="@drawable/apple" />

    <TextView
        android:id="@+id/fruit_text"
        android:layout_width="90dp"
        android:layout_height="50dp"
        android:layout_marginLeft="10dp"
        android:gravity="center_vertical"
        android:text="Apple"
        android:textSize="18dp" />

</LinearLayout>

这个也很简单,我们想让这个listView显示什么样式呢,就在这个里面做就行,现在我做的,就是左边一个水果图片,右边一个名字。然后,我们写一个方便调用的工具类,代码如下


/**
 * 工具类
 */

public class Fruits {

    private String name;

    private int imageId;

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

    public String getName() {
        return name;
    }

    public int getImageId() {
        return imageId;
    }
}

接下来就是重头戏了,适配器,listview的适配器有很多种,这本书里使用的是ArrayAdapter,所以,我也是,看代码

/**
 * 适配器
 */

public class FruitAdapter extends ArrayAdapter<Fruits> {

    private int resourceId;

    /**
     * 重写方法,方便之后调用
     * @param context 上下文
     * @param textViewResourceId 要绑定的布局文件
     * @param objects 布局文件里面要使用的数据,(函数)
     */
    public FruitAdapter(Context context, int textViewResourceId, List<Fruits> objects) {
        super(context,  textViewResourceId, objects);
        this.resourceId = textViewResourceId;
    }


    /**
     * 重写getView方法,在这个方法里面做数据的绑定等操作
     * @param position 当前的item
     * @param convertView 缓存的数据
     * @param parent 父布局
     * @return
     */
    @NonNull
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Fruits fruits = getItem(position); //获取当前的item的实例
        View view;
        final ViewHoder viewHoder; //为了优化listview创建的一个内部类,可以不用每次都重新创建item的实例
        //如果缓存为空的话,就创建view,,否则,就复用缓存的view(这么做的前提是,每个view的布局都一样)
        if (convertView == null) {
            view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
            viewHoder = new ViewHoder();
            viewHoder.fruitText = (TextView) view.findViewById(R.id.fruit_text);
            viewHoder.fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
            viewHoder.fruitText.setText(fruits.getName());
            viewHoder.fruitImage.setImageResource(fruits.getImageId());
            view.setTag(viewHoder);//将viewHolder的实例存储在view里面
        }else {
            view = convertView;
            viewHoder = (ViewHoder) view.getTag();//如果没有缓存就取出来
            viewHoder.fruitText.setText(fruits.getName());
            viewHoder.fruitImage.setImageResource(fruits.getImageId());
        }
        return view;
    }

    private class ViewHoder {
        TextView fruitText;
        ImageView fruitImage;
    }
}

很麻烦是吧,我在这遇到了一个坑,大家可以看到,在 if 和 else 里面有两行相同的代码,是给图片和名字赋值的。这时候有人问了,既然viewHolder的实例已经存储在view里边了,为什么还要再次赋值呢?思维盲点啊,我也想半天啊,它存储的是实例啊,不重新赋值的话,拿到的值每次都不一样的啊。

  viewHoder.fruitText.setText(fruits.getName());  viewHoder.fruitImage.setImageResource(fruits.getImageId());

我试了一下,不再次赋值,也能成功运行。但是,每次出现的数据都不同的。想要数据正确,请千万记得重新赋值。好吧,我这个脑子容易出这种乱七八糟的错误,如果有同样错的。希望能帮到你。
对了,还有最后MainActivity的代码:

public class MainActivity extends AppCompatActivity {

    //创建一个集合,待会要放数据的
    private List<Fruits> fruitList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //这个方法里边全是数据
        initFruit();
        //适配器,要记得绑定你定样式的那个布局文件
        FruitAdapter adapter = new FruitAdapter(MainActivity.this,
                R.layout.fruit_item, fruitList);
        ListView listView = (ListView) findViewById(R.id.list_view);

        listView.setAdapter(adapter);
    }

    //写了个for循环,数据太少,不循环的话不够滑动页面的
    private void initFruit() {
        for (int i = 0; i < 5; i++) {
            Fruits apple = new Fruits("Apple", R.drawable.apple);
            fruitList.add(apple);
            Fruits banana = new Fruits("Banana", R.drawable.banana);
            fruitList.add(banana);
            Fruits cherry = new Fruits("Cherry", R.drawable.cherry);
            fruitList.add(cherry);
            Fruits grape = new Fruits("Grape", R.drawable.grape);
            fruitList.add(grape);
            Fruits orange = new Fruits("Orange", R.drawable.orange);
            fruitList.add(orange);
            Fruits pear = new Fruits("Pear", R.drawable.pear);
            fruitList.add(pear);
            Fruits watermelon = new Fruits("WatermeIon", R.drawable.watermelon);
            fruitList.add(watermelon);
        }
    }
}

嗯,基本就这样了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值