《第一行代码》阅读笔记(十)——RecyclerView

按照书上的说法就是RecycleView更强大!而且目前来看ListView基本上已经淘汰了,所以让我们来看看RecycleView吧。

导包

因为版本更新,书上的已经过时了,所以我百度了一下,发现了这个两个版本。

v7:implementation 'com.android.support:recyclerview-v7:28.0.0'
x:implementation 'androidx.recyclerview:recyclerview:1.1.0'

参考文章:Android Studio新版本导入Recyclerview库的依赖
总是听到有人说AndroidX,到底什么是AndroidX?

简单来说就是Androidx比较新,v7比较老,同时两个包不能同时使用,会在某些地方出现冲突。一般现在都用x了

案例

第一步:修改activity_ main.xml

  <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

其实就是把之前的ListView改成RecyclerView,但是RecyclerView需要全类名

第二步:给RecyclerView新建一个适配器
先把ListView项目的Fruit类和fruit_item布局复制过来,可以去上一个章节寻找相关资料。

package com.firstcode.customuicontrols;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.List;

import androidx.recyclerview.widget.RecyclerView;

public class FruitRecyclerViewAdapter extends RecyclerView.Adapter<FruitRecyclerViewAdapter.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.image_view);
            fruitName = (TextView) view.findViewById(R.id.text_view);
        }
    }


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

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_fruit, 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();
    }
}

因为避免和上一个案例重复,我自己修改了类名,其他的都是一样的。

这里说一下笔者的理解,首先就是使用了一个内部类,实现了RecyclerView每个子项的初始化。这个用法理解起来还是比较复杂的,笔者个人的理解就是内部类的形式实例化一个View,然后可以对其进行很多的操作。

第二部分就是整个适配器的构造函数,可以看出RecyclerView的适配器只需要传入一个数组即可。因为它把子项控件的初始化和布局的加载通过其他函数内置了,就是内部类和onCreateViewHolder。

onCreateViewHolder就是初始化,加载布局的。同样是使用LayoutInflater方法,但是我发现只要在Activity中,环境变量才能使用Activity或者this,而在其他的类中大多数使用View的方法getContext。这也间接的说明View和Activity就是环境。

onBindViewHolder通过书上的介绍就是在每个子项展示的时候调用,就是很简单的通过位置设置值。

最后一个函数就是返回数组长度。

但是笔者这里发现inflate的参数和之前自定义控件时候使用的不同。搜索了一下,发现其有四个构造函数。

这里有个新的概念就是ViewGroup,其实简单的来说就是像LinearLayout 之类的布局就是ViewGroup,而那些控件像Button就是一种View,View是ViewGroup的父类。到这里我就明白inflate的含义了。

先说为什么之前使用的inflate是两个参数的,它使用的是图中第一个构造函数,int类型的是布局id,而ViewGroup就是父布局,当时传入的是当前的Activity,其实Activity也是一个View。
而Adapter为啥要传入三个参数,因为Adapter是为list服务的,list自己有一个总体的布局,而他的子项也是一个布局,需要加载其中。所以使用图中第三个构造函数,最后的布尔型参数取消新建布局,把子布局放到list的子项里面。

参考资料
基础篇——View和ViewGroup的区别
Android LayoutInflate深度解析
Android View原理浅析——View的工作原理
Android View详解

第三步:修改MainActivity

RecyclerView recyclerView = (RecyclerView) findViewById(R.id.list_view);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
        FruitRecyclerViewAdapter adapter = new FruitRecyclerViewAdapter(fruitList);
        recyclerView.setAdapter(adapter);

横向滑动

第一步 修改布局

其实就是把原来的横向布局改为竖向,文字和图片调整大小

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

    <ImageView
        android:id="@+id/image_view"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_gravity="center_horizontal"/>

    <TextView
        android:id="@+id/text_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="10dp"/>


</LinearLayout>

第二步:加载布局
只有一个操作,在之前加载布局前设置横向设置

        layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);

瀑布布局

第一步还是修改布局

<?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"
    android:layout_margin="5dp"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/image_view"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_gravity="center_horizontal" />

    <TextView
        android:id="@+id/text_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="left"
        android:layout_marginTop="10dp" />


</LinearLayout>

第二步是也是一样的加载布局,同样的只需要一行代码就行了。

StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(staggeredGridLayoutManager);

网格布局

到这里我已经感受到了RecycleView的强大之处,在于可以在List之上添加布局,虽然有些地方还是不明白。书中并没有网格布局的代码,也是留了个作业,所以我们就在这做一下,练练手。

在网上查阅了资料发现GridLayoutManager有两个参数,第一个就是上下文,第二个就是列数。
所以修改代码如下

GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 2);
        recyclerView.setLayoutManager(gridLayoutManager);

点击事件

第一步:修改适配器代码

具体代码修改不多,和之前的按钮的点击事件相似。大家看看书本上的讲解应该就能明白。

规范

  1. 在实际开发中一般不使用构造函数来赋值,会写一个setData()方法来传入数据。这样可以保证实例化和赋值分开,减少错误。
  2. 点击事情写在ViewHolder里面,在onBindView方法中调用,这样结构更加清晰。
原文地址:https://www.cnblogs.com/zllk/p/13363729.html