由于ListView只能实现数据纵向(垂直)方向的滚动效果,不能实现横向(水平)方向的滚动效果。因此,android官方更加推荐使用RecyclerView。

RecyclerView可以说是ListView的加强版,不仅可以实现和ListView同样的效果,还优化了ListView的不足之处,同时具有很好的扩展性(实现横向布局,网格布局,瀑布流布局)

RecyclerView是android新增的控件,为了能在所有android版本上使用,需要将它定义在support库中,即在项目的build.gradle中添加相应的依赖库。

实例:
activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context="com.sky.recyclerviewdemo.MainActivity"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/btnVertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Vertical Layout"
        android:textAllCaps="false"/>
    <Button
        android:id="@+id/btnHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Horizontal Layout"
        android:textAllCaps="false"/>
    <Button
        android:id="@+id/btnGrid"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Grid Layout"
        android:textAllCaps="false"/>
    <Button
        android:id="@+id/btnStaggered"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Staggered Grid Layout"
        android:textAllCaps="false"/>
</LinearLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private Button btnVertical;
    private Button btnHorizontal;
    private Button btnGrid;
    private Button btnStaggered;
    private Intent intent;

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

        initView();
    }

    private void initView() {
        btnVertical = (Button)findViewById(R.id.btnVertical);
        btnHorizontal = (Button)findViewById(R.id.btnHorizontal);
        btnGrid = (Button)findViewById(R.id.btnGrid);
        btnStaggered = (Button)findViewById(R.id.btnStaggered);

        btnVertical.setOnClickListener(this);
        btnHorizontal.setOnClickListener(this);
        btnGrid.setOnClickListener(this);
        btnStaggered.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.btnVertical:
                intent = new Intent(MainActivity.this, VerticalActivity.class);
                startActivity(intent);
                break;
            case R.id.btnHorizontal:
                intent = new Intent(MainActivity.this, HorizontalActivity.class);
                startActivity(intent);
                break;
            case R.id.btnGrid:
                intent = new Intent(MainActivity.this, GridActivity.class);
                startActivity(intent);
                break;
            case R.id.btnStaggered:
                intent = new Intent(MainActivity.this, StaggeredActivity.class);
                startActivity(intent);
                break;
            default:
        }
    }
}

一、RecyclerView的基本用法(垂直布局)
主界面布局:activity_vertical.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.sky.recyclerviewdemo.VerticalActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/vertical_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

RecyclerView代码实现VerticalActivity.class

public class VerticalActivity extends AppCompatActivity {

    private List<YYPicture> picList = new ArrayList<>();
    // 数据资源
    private int[] data = {
            R.drawable.pic_1, R.drawable.pic_2, R.drawable.pic_3,
            R.drawable.pic_4, R.drawable.pic_5, R.drawable.pic_6,
            R.drawable.pic_7, R.drawable.pic_8, R.drawable.pic_9,
            R.drawable.pic_10, R.drawable.pic_11, R.drawable.pic_12,
            R.drawable.pic_13, R.drawable.pic_14, R.drawable.pic_15,
    };

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

        initData();
        initView();
    }
    // 初始化数据,将数据添加到列表中
    private void initData() {
        for(int i=0; i<data.length; i++){
            YYPicture yypic = new YYPicture(data[i]);
            picList.add(yypic);
        }
    }

    private void initView() {
        RecyclerView recyclerView = (RecyclerView)findViewById(R.id.vertical_recycler_view);

        // 指定RecyclerView的布局方式
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        // 设置布局的排列方向,默认是纵向排列
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(layoutManager);

        // 加载数据,完成适配器设置
        PictureAdapter adapter = new PictureAdapter(picList);
        recyclerView.setAdapter(adapter);

    }
}

YYPicture类实现YYPicture.java

public class YYPicture {
    // 资源ID
    private int picId;
    public YYPicture(int id){
        this.picId = id;
    }

    public int getPicID() {
        return picId;
    }
}

PictureAdapter适配器实现PictureAdapter.java

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

    private  List<YYPicture> yyPictureList;

    public PictureAdapter(List<YYPicture> pictureList){
        yyPictureList = pictureList;
    }

    static class ViewHolder extends RecyclerView.ViewHolder {
        ImageView imageView;
        public ViewHolder(View itemView) {
            super(itemView);
            imageView = (ImageView)itemView.findViewById(R.id.imageView);
        }
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        // 加载子项布局
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.picture_item, parent, false);
        ViewHolder holder = new ViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        YYPicture yyPicture = yyPictureList.get(position);
        holder.imageView.setImageResource(yyPicture.getPicID());
    }

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

}

picture_item.xml 是加载到RecyclerView子项的布局文件

<?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/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

从上诉代码中可以看出,最主要的实现还是在adapter上。
首先新建一个PictureAdapter类,继承RecyclerView.Adapter,并将泛型指定为PictureAdapter.ViewHolder。ViewHolder为PictureAdapter中定义的一个内部类。

ViewHolder内部类,继承RecyclerView.ViewHolder。ViewHolder的构造函数中要传入一个View参数。通常这个参数就是RecyclerView子项的最外层布局,然后通过这个参数,我们就可以通过findViewById()方法来获取到布局中的id。

PictureAdapter构造函数,这个方法主要用于将数据源传入,并将它赋值给全局变量yyPictureList ,后续就可以通过yyPictureList 操作数据了。

由于PictureAdapter是继承RecyclerView.Adapter的,那么就必须重写onCreateViewHolder()和onBindViewHolder()以及getItemCount()这3个方法。

onCreateViewHolder()方法,用于创建ViewHolder实例,并将加载的布局传入ViewHolder构造函数中,最后将ViewHolder的实例返回。

onBindViewHolder()方法,用于对RecyclerView子项的数据进行赋值,当子项数据被滚动到屏幕内是调用。

getItemCount()方法,用于返回数据源的长度。


二、RecyclerView的横向滚动(水平排列)
还记得指定RecyclerView的布局方式吗?嘿嘿。。。。
要想实现横向滚动的效果,只需要将RecyclerView布局设置为水平排列就行了。

// 指定RecyclerView的布局方式
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        // 设置布局的排列方向,默认是纵向排列
        // layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        // 设置布局为水平排列
        layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);

        recyclerView.setLayoutManager(layoutManager);

即,改成layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);就可以咯。

这里就不在写HorizontalActivity的实现了。。。


不管是修改主界面布局(activity_vertical.xml)还是修改加载到RecyclerView子项的布局文件(picture_item.xml )的orientation属性,都是不能改变RecyclerView的排列方式。

只能通过LinearLayoutManager的setOrientation()方法来设置排列方向。


三、RecyclerView的网格布局 – GridLayoutManager
同样的,只需要将RecyclerView布局方式修改成GridLayoutManager 即可。

这里就不在写HorizontalActivity的实现了。。。
修改如下:

// 指定RecyclerView的布局方式:线性布局
        //LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        // 设置布局的排列方向,默认是纵向排列
        // layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        // 设置布局为水平排列
        // layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);

        // 指定RecyclerView的布局方式:网格布局
        GridLayoutManager layoutManager = new GridLayoutManager(this,3);
        recyclerView.setLayoutManager(layoutManager);

四、RecyclerView的交错网格布局(也叫瀑布流布局) – StaggeredGridLayoutManager
同样的,只需要将RecyclerView布局方式修改成StaggeredGridLayoutManager
即可。
修改如下:

// 指定RecyclerView的布局方式:线性布局
        // LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        // 设置布局的排列方向,默认是纵向排列
        // layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        // 设置布局为水平排列
        // layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);

        // 指定RecyclerView的布局方式:网格布局
        // GridLayoutManager layoutManager = new GridLayoutManager(this,3);

        // 指定RecyclerView的布局方式:交错网格布局(瀑布流式布局)
        StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(layoutManager);

只不过如果图片大小都一样的话,那看起来就跟网格布局一样了。所以可以通过修改图片大小打乱排序,即可程序效果。


五、RecyclerView的点击事件
RecyclerView并没有像ListView一样,有提供setOnItemClickListener()这样的注册监听器方法,它需要由用户自己为子项中具体的View注册点击事件。这样的话,它就可以轻松的实现子项中任意控件或者布局的点击事件。

holder.imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                int position = holder.getAdapterPosition();
                YYPicture yyPicture = yyPictureList.get(position);
                Toast.makeText(view.getContext(), "2222222", Toast.LENGTH_SHORT).show();
            }
        });