Android ListView 和 RecyclerView 详解

1、ListView
由于手机屏幕空间有限,能够一次性在屏幕上显示的内容并不多,当程序中有大量的数据需要展示的时候,就可以借助 ListView 来实现。ListView 允许用户通过手指上下滑动的方式将屏幕外的数据滚动到屏幕内。

(1)、ListView 的简单用法
首先新建一个项目,修改 activity_main.xml 中的代码,如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ListView
        android:id="@+id/list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></ListView>
</LinearLayout>

然后修改 MainActivity 中代码,如下:

public class MainActivity extends AppCompatActivity {
    private String[] data = {"Apple1", "Apple2", "Apple3", "Apple4", "Apple5", "Apple6",
            "Apple7", "Apple8", "Apple9", "Apple10", "Apple11", "Apple12", "Apple13", "Apple14",
            "Apple15", "Apple16", "Apple17", "Apple18", "Apple19", "Apple20"};
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ArrayAdapter<String> adapter = new ArrayAdapter<String>(
                MainActivity.this, android.R.layout.simple_list_item_1, data
        );
        ListView listView = (ListView) findViewById(R.id.list_view);
        listView.setAdapter(adapter);
    }
}

ListView 展示的数据可以是从网上下载的,也可以是从数据库读取的,根据不同的情景来设定。这里我们使用一个data数组来测试。
不过数组中的数据是无法直接传递给 ListView 的,我们还需要借助适配器来完成,这里我们使用 ArrayAdapter。它可以使用泛型来指定要适配的数据类型,然后再构造函数中把要适配的数据传入。这里我们提供的数据是字符串,因此将 ArrayAdapter 的泛型指定为 String,然后再 ArrayAdapter 的构造函数中依次传入当前上下文、ListView 子项布局的id,以及要适配的数据。注意 android.R.layout.simple_list_item_1 作为 ListView 子项布局的id,这是一个 Android 内置的布局文件,里面只包含一个 TextView。
最后,调用 ListView 的 setAdapter() 方法,将构建好的适配器对象传递进去。
在这里插入图片描述

效果图
(2)、定制 ListView 的界面
准备一组图片,分别对应上面提供的每一种水果。
首先新建一个实体类,作为 ListView 适配器的适配类型。新建类 Fruit,Fruit 只包含两个字段,name 表示名称,imageId表示水果对应图片的资源id,如下:

public class Fruit {
    private String name;
    private int imageId;
    public Fruit(String name, int imageId) {
        this.name = name;
        this.imageId = imageId;
    }
    public String getName() {
        return name;
    }
    public int getImageId() {
        return imageId;
    }
}

然后为 ListView 的子项指定一个我们自定义的布局,新建 fruit_item.xml,在这个布局中我们定义了一个 ImageView 来显示水果图片,定义了一个 TextView 用于显示水果的名称。代码如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView
        android:id="@+id/fruit_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/fruit_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="10dp" />
</LinearLayout>

接下来创建一个自定义的适配器,这个适配器继承自 ArrayAdapter,并将泛型真得 Fruit 类。新建类 FruitAdapter,如下:

public class FruitAdapter extends ArrayAdapter<Fruit> {
    private int resourceId;
    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) {
        Fruit fruit = getItem(position); // 获取当前项的Fruit实例
        View view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
        ImageView fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
        TextView fruitName = (TextView) view.findViewById(R.id.fruit_name);
        fruitImage.setImageResource(fruit.getImageId());
        fruitName.setText(fruit.getName());
        return view;
    }
}

FruitAdapter 重写了父类的一组构造函数,用于将上下文、ListView 子项布局的id和数据都传递进来。另外重写了 getView() 方法。这个方法在每个子项被滚到屏幕内的时候会被调用。在 getView() 方法中,首先通过 getItem() 方法得到当前项的 Fruit 实例,然后使用 LayoutInflater 来为这个子项加载我们传入的布局。
然后修改 MainActivity 中的代码,如下所示:

public class MainActivity extends AppCompatActivity {

    private List<Fruit> fruitList = new ArrayList<Fruit>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initFruits();
        FruitAdapter adapter = new FruitAdapter(MainActivity.this,R.layout.fruit_item,fruitList);
        ListView listView = (ListView) findViewById(R.id.list_view);
        listView.setAdapter(adapter);
    }

    private void initFruits() {
        for (int i = 0; i < 2; i++) {
            Fruit apple = new Fruit("Apple", R.drawable.apple_pic);
            fruitList.add(apple);
            Fruit banana = new Fruit("Banana", R.drawable.banana_pic);
            fruitList.add(banana);
            Fruit orange = new Fruit("Orange", R.drawable.orange_pic);
            fruitList.add(orange);
            Fruit watermelon = new Fruit("Watermelon", R.drawable.watermelon_pic);
            fruitList.add(watermelon);
            Fruit pear = new Fruit("Pear", R.drawable.pear_pic);
            fruitList.add(pear);
            Fruit grape = new Fruit("Grape", R.drawable.grape_pic);
            fruitList.add(grape);
            Fruit pineapple = new Fruit("Pineapple", R.drawable.pineapple_pic);
            fruitList.add(pineapple);
            Fruit strawberry = new Fruit("Strawberry", R.drawable.strawberry_pic);
            fruitList.add(strawberry);
            Fruit cherry = new Fruit("Cherry", R.drawable.cherry_pic);
            fruitList.add(cherry);
            Fruit mango = new Fruit("Mango", R.drawable.mango_pic);
            fruitList.add(mango);
        }
    }
}

在这里添加了一个 initFruits()方法,用于初始化所有的水果数据。创建 Fruit 对象,然后把创建好的对象添加到水果列表中。接着在 onCreate() 方法中创建了 FruitAdapter 对象,并将 FruitAdapter 作为适配器传递给 ListView。
在这里插入图片描述

效果图
(3)、提升ListView 的运行效率
在使用 ListView 时有很多细节可以优化,其中运行效率就是很重要的一点。目前我们 ListView 的运行效率是很低的,因为在 FruitAdapter 的 getView() 方法中,每次都将布局重新加载了一遍,当 ListView 快速滚动的时候,这就会成为性能的瓶颈。
在 getView() 方法中有一个 convertView 参数,这个参数用于将之前加载喊的布局进行缓存,以便之后可以进行重用,修改 FruitAdapter,如下所示:

public class FruitAdapter extends ArrayAdapter<Fruit> {
    ...
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Fruit fruit = getItem(position); // 获取当前项的Fruit实例
        View view;
        if (convertView == null) {
            view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
        } else {
            view = convertView;
        }
        ImageView fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
        TextView fruitName = (TextView) view.findViewById(R.id.fruit_name);
        fruitImage.setImageResource(fruit.getImageId());
        fruitName.setText(fruit.getName());
        return view;
    }
}

在getView()方法中进行了判断,如果 convertView 为null,则使用 LayoutInflater 去加载布局,如果不为null则直接对 convertView 进行重用。这样就大大提高了 ListView 的运行效率,在快速滚动的时候也可以表现出更好的性能。
目前虽然已经不会再重复去加载布局,但是每次在 getView() 方法中还是会调用 View 的 findViewById() 方法来获取一次控件的实例。我们可以借助一个 ViewHolder 来对这部分性能进行优化修改代码,修改代码,如下如下:

public class FruitAdapter extends ArrayAdapter<Fruit> {
    private int resourceId;

    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) {
        Fruit fruit = getItem(position); // 获取当前项的Fruit实例
        View view;
        ViewHolder viewHolder;
        if (convertView == null) {
            view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
            viewHolder = new ViewHolder();
            viewHolder.fruitImage = (ImageView) view.findViewById (R.id.fruit_image);
            viewHolder.fruitName = (TextView) view.findViewById (R.id.fruit_name);
            view.setTag(viewHolder); // 将ViewHolder存储在View中
        } else {
            view = convertView;
            viewHolder = (ViewHolder) view.getTag(); // 重新获取ViewHolder
        }
        viewHolder.fruitImage.setImageResource(fruit.getImageId());
        viewHolder.fruitName.setText(fruit.getName());
        return view;
    }
    class ViewHolder {

        ImageView fruitImage;

        TextView fruitName;
    }
}

我们新增了一个内部类 ViewHolder ,用于对控件的实例进行缓存。当 convertView 为null时,创建 ViewHolder 对象,并将控件的实例存放在 ViewHolder 里,然后调用 View 的 setTag() 方法,将 ViewHolder 对象存储在View 中。当 convertView 部null的时候,则调用View的 getTag() 方法,把 ViewHolder 重新取出。这样所有控件的实例缓存在了 ViewHolder 里,就不用每次都通过 findViewById() 方法来获取控件的实例了。

(4)、ListView 的点击事件
修改 MainActivity 中的 onCreate() 方法,如下:

   protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initFruits(); // 初始化水果数据
        FruitAdapter adapter = new FruitAdapter(MainActivity.this, R.layout.fruit_item, fruitList);
        ListView listView = (ListView) findViewById(R.id.list_view);
        listView.setAdapter(adapter);
        listView.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();
            }
        });
    }

我们使用 setOnItemClickListener() 方法为 ListView 注册了一个监听器,当用户点击了 ListView 中任何一个子项时,就会回调 onItemClick() 方法。在这个方法中可以通过 position 参数判断出用户点击的是哪一个子项。

2、RecyclerView
RecyclerView 可以说是一个增强版的ListView,不仅可以轻松实现和 ListView 同样的效果,还优化了 ListView 中存在的各种不足之处。

(1)、RecyclerView 的基本用法
和百分比布局类似,RecyclerView 也属于新增控件,为了让 RecyclerView 在所有 Android 版本上都能使用,将 RecyclerView 定义在了 support 库当中。因此首先要在项目的 build.gradle 中添加相应的依赖库才行。

dependencies {
    ...
    implementation 'com.android.support:recyclerview-v7:24.2.1'
}

然后修改 antivity_main.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.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </android.support.v7.widget.RecyclerView>
</LinearLayout>

将之前的 Fruit 类和 fruit_item.xml 也复制过来。然后为 RecyclerView 准备一个适配器,新建 FruitAdapter 类,让这个适配器继承自 RecyclerView.Adapter,并将泛型指定为 FruitAdapter.ViewHolder。其中 ViewHolder 是我们在 FruitAdapter 中定义的一个内部类,代码如下:

public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder>{

    private List<Fruit> mFruitList;

    static class ViewHolder extends RecyclerView.ViewHolder {
        ImageView fruitImage;
        TextView fruitName;

        public ViewHolder(View view) {
            super(view);
            fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
            fruitName = (TextView) view.findViewById(R.id.fruit_name);
        }
    }

    public FruitAdapter(List<Fruit> fruitList) {
        mFruitList = fruitList;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.fruit_item, parent, false);
        ViewHolder holder = new ViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Fruit fruit = mFruitList.get(position);
        holder.fruitImage.setImageResource(fruit.getImageId());
        holder.fruitName.setText(fruit.getName());
    }

    @Override
    public int getItemCount() {
        return mFruitList.size();
    }
}

这里首先定义了一个内部类 ViewHolder ,ViewHolder 要继承自 RecyclerView.ViewHolder,然后 ViewHolder 的构造函数中要传入一个 View 参数,这个参数通常就说 RecyclerView 子项的最外层布局,那么我们就可以通过 findViewById() 方法来获取到布局中的ImageView和TextView的实例了。
在 FruitAdapter 的构造函数中用于将要展示的数据源传进来,并赋值给一个全局变量 mFruitList。由于 FruitAdapter 继承自 RecyclerView.ViewHolder 的,就必须重写 onCreateViewHolder()、onBindViewHolder()、getItemCount()这3个方法。onCreateViewHolder() 方法用于创建 ViewHolder 实例,我们在这个方法中将 fruit_item 布局加载进来,然后创建一个 ViewHolder 实例,并把加载出来的布局传入到构造函数当中,最后将 ViewHolder 实例返回。onBindViewHolder() 方法是用于对RecyclerView子项的数据进行赋值的,会在每个子项被滚动到屏幕内的时候执行,这里我们通过 position 参数得到当前 Fruit 实例,然后再将数据设置到 ViewHolder 的 ImageView 和 TetView 中。getItemCount() 返回数据源的长度。
修改 MainActivity 中的代码:

public class MainActivity extends AppCompatActivity {

    private List<Fruit> fruitList = new ArrayList<Fruit>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initFruits();
        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
        FruitAdapter adapter = new FruitAdapter(fruitList);
        recyclerView.setAdapter(adapter);
    }

    private void initFruits() {
        for (int i = 0; i < 2; i++) {
            Fruit apple = new Fruit("Apple", R.drawable.apple_pic);
            fruitList.add(apple);
            Fruit banana = new Fruit("Banana", R.drawable.banana_pic);
            fruitList.add(banana);
            Fruit orange = new Fruit("Orange", R.drawable.orange_pic);
            fruitList.add(orange);
            Fruit watermelon = new Fruit("Watermelon", R.drawable.watermelon_pic);
            fruitList.add(watermelon);
            Fruit pear = new Fruit("Pear", R.drawable.pear_pic);
            fruitList.add(pear);
            Fruit grape = new Fruit("Grape", R.drawable.grape_pic);
            fruitList.add(grape);
            Fruit pineapple = new Fruit("Pineapple", R.drawable.pineapple_pic);
            fruitList.add(pineapple);
            Fruit strawberry = new Fruit("Strawberry", R.drawable.strawberry_pic);
            fruitList.add(strawberry);
            Fruit cherry = new Fruit("Cherry", R.drawable.cherry_pic);
            fruitList.add(cherry);
            Fruit mango = new Fruit("Mango", R.drawable.mango_pic);
            fruitList.add(mango);
        }
    }
}

这里我们同样使用了 initFruits() 方法,用于初始化数据。然后在 onCreate() 方法中,我们先获取到 RecyclerView 的实例,然后创建了一个 LinearLayoutManager 对象,并将它设置到 RecyclerView 当中。 LayoutManager 用于指定 RecyclerView 的布局方式,LinearLayoutManager 是线性布局的意思,可以实现和 ListView 类似的效果。接下来创建了 FruitAdapter 实例,并将数据传入到其构造函数中,最后调用 RecyclerView 的 setAdapter() 方法来完成适配器设置。
在这里插入图片描述

效果图
(2)、实现横向滚动和瀑布流布局
使用 RecyclerView 实现横向滚动。因为目前这个布局里的元素是水平排列的,适用于纵项滚动的场景,如果需要实现横向滚动的话,应该把 fruit_item 里的元素改为成垂直排列。修改 fruit_item.xml 中的代码:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="100dp"
    android:layout_height="wrap_content">
    <ImageView
        android:id="@+id/fruit_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"/>
    <TextView
        android:id="@+id/fruit_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="10dp" />
</LinearLayout>

接下来修改 MainActivity 中的代码

public class MainActivity extends AppCompatActivity {
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initFruits();
        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        //新增
        layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);

        recyclerView.setLayoutManager(layoutManager);
        FruitAdapter adapter = new FruitAdapter(fruitList);
        recyclerView.setAdapter(adapter);
    }
    ...
}

MainActivity 中加入了一行代码,调用 LinearLayoutManager 的 setOrientation() 方法来设置布局的排列方向,默认为纵向排列,LinearLayoutManager.HORIZONTAL 表示横向排列。
在这里插入图片描述

效果图

RecyclerView 能实现 ListView 很难或者根本不能实现的效果主要是因为 ListView 的布局排列是由自身去管理的,而 RecyclerView 则将这个工作交给了 LayoutManager ,LayoutManager 中定制了一套可扩展的布局排列接口,子类只要按照接口的规范来实现,就能定制出各种不同排列方式的布局了。

使用 RecyclerView 实现瀑布流布局。除了 LinearLayoutManager 之外 RecyclerView 还提供了 GridLayoutManager 用于实现网格布局,StaggeredGridLayoutManager 用于实现瀑布流布局。下面实现瀑布流布局,修改 fruit_item.xml 中的部分属性 :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="5dp">
    <ImageView
        android:id="@+id/fruit_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"/>
    <TextView
        android:id="@+id/fruit_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="left"
        android:layout_marginTop="10dp" />
</LinearLayout>

接着修改 MainActivity 中的代码,如下所示:

public class MainActivity extends AppCompatActivity {

    private List<Fruit> fruitList = new ArrayList<Fruit>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initFruits();
        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        StaggeredGridLayoutManager layoutManager = new
                StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(layoutManager);
        FruitAdapter adapter = new FruitAdapter(fruitList);
        recyclerView.setAdapter(adapter);
    }

    private void initFruits() {
        for (int i = 0; i < 2; i++) {
            Fruit apple = new Fruit(getRandomLengthName("Apple"), R.drawable.apple_pic);
            fruitList.add(apple);
            Fruit banana = new Fruit(getRandomLengthName("Banana"), R.drawable.banana_pic);
            fruitList.add(banana);
            Fruit orange = new Fruit(getRandomLengthName("Orange"), R.drawable.orange_pic);
            fruitList.add(orange);
            Fruit watermelon = new Fruit(getRandomLengthName("Watermelon"), R.drawable.watermelon_pic);
            fruitList.add(watermelon);
            Fruit pear = new Fruit(getRandomLengthName("Pear"), R.drawable.pear_pic);
            fruitList.add(pear);
            Fruit grape = new Fruit(getRandomLengthName("Grape"), R.drawable.grape_pic);
            fruitList.add(grape);
            Fruit pineapple = new Fruit(getRandomLengthName("Pineapple"), R.drawable.pineapple_pic);
            fruitList.add(pineapple);
            Fruit strawberry = new Fruit(getRandomLengthName("Strawberry"), R.drawable.strawberry_pic);
            fruitList.add(strawberry);
            Fruit cherry = new Fruit(getRandomLengthName("Cherry"), R.drawable.cherry_pic);
            fruitList.add(cherry);
            Fruit mango = new Fruit(getRandomLengthName("Mango"), R.drawable.mango_pic);
            fruitList.add(mango);
        }
    }

    private String getRandomLengthName(String name) {
        Random random = new Random();
        int length = random.nextInt(20) + 1;
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < length; i++) {
            builder.append(name);
        }
        return builder.toString();
    }
}

在 onCreate() 方法中,创建了一个 StaggeredGridLayoutManager 的实例。StaggeredGridLayoutManager 的构造函数接收两个参数,第一个参数用于指定布局的列数,传入3表示3列;第二个参数用于指定布局的排列方向,StaggeredGridLayoutManager.VERTICAL 表示纵向布局。不过由于瀑布流布局需要各个子项高度不一致才能看出想过,所以修改 initFruits() 方法。
在这里插入图片描述

效果图

使用 RecyclerView 实现网格布局。修改 MainActivity 中的代码

GridLayoutManager layoutManager=new GridLayoutManager(this,3);
可以看到GridLayoutManager需要传递两个参数,一个是上下文对象,另一个是一行显示几列的参数常量。通过效果图能够很清晰的看出网格布局与瀑布流布局直接的差别。
在这里插入图片描述

效果图
(3)、RecyclerView 的点击事件
不同与 ListView 的是,RecyclerView 并没有提供类似与 setOnItemClickListener() 这样的注册监听方法,而是需要我们自己给子项具体的 View 去注册监听事件。
修改 FruitAdapter 中的代码:

public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {

    private List<Fruit> mFruitList;

    static class ViewHolder extends RecyclerView.ViewHolder {
        View fruitView;
        ImageView fruitImage;
        TextView fruitName;

        public ViewHolder(View view) {
            super(view);
            fruitView = view;
            fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
            fruitName = (TextView) view.findViewById(R.id.fruit_name);
        }
    }

    public FruitAdapter(List<Fruit> fruitList) {
        mFruitList = fruitList;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.fruit_item, parent, false);
        final ViewHolder holder = new ViewHolder(view);
        holder.fruitView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = holder.getAdapterPosition();
                Fruit fruit = mFruitList.get(position);
                Toast.makeText(v.getContext(),"View "+ fruit.getName(),Toast.LENGTH_LONG).show();
            }
        });
        holder.fruitImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = holder.getAdapterPosition();
                Fruit fruit = mFruitList.get(position);
                Toast.makeText(v.getContext(),"Image  "+ fruit.getName(),Toast.LENGTH_LONG).show();
            }
        });
        return holder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Fruit fruit = mFruitList.get(position);
        holder.fruitImage.setImageResource(fruit.getImageId());
        holder.fruitName.setText(fruit.getName());
    }

    @Override
    public int getItemCount() {
        return mFruitList.size();
    }
}

我们先修改了 ViewHolder,在 ViewHolder 中添加了 fruitView 变量来保存子项最外层的实例,然后在 onCreateViewHolder() 方法中注册点击事件就行了。这里分别为最外层布局和 ImagView 都注册了点击事件,。RecyclerView 可以轻松实现子项任意控件或布局的点击事件。在点击事件中,先获取用户点击的 position ,然后通过 position 获取Fruit的实例。

作者:zda123000
链接:https://www.jianshu.com/p/da23fe946ed1
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值