浅谈RecyclerView(完美替代ListView,GridView)

Android RecyclerView 是Android5.0推出来的,导入support-v7包即可使用。

个人体验来说,RecyclerView绝对是一款功能强大的控件。

首先总结下RecyclerView的特点:

1.支持不同方向,不同排版模式,实现多种展现数据的形式,涵盖了ListView,GridView,瀑布流等数据表现的形式

2.内部实现了回收机制,无需我们考虑View的复用情况

3.取消了onItemClick等点击事件,需要自己手动去写

------------------------------------------------------------------------------------

那么让我们通过一些Demo来了解RecyclerView的基本使用

 android studio 

build.gradle文件中 dependencies中添加 

compile 'com.android.support:recyclerview-v7:22.+'

首先,要导入support-v7 包

import android.support.v7.widget.RecyclerView;

RecyclerView和ListView的使用一样,都需要有对应的Adapter,列表项布局,数据源

1.先写主Activity布局

可以看到RecyclerView的标签

<android.support.v7.widget.RecyclerView>
 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2               xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto"
 3               android:layout_width="match_parent"
 4               android:layout_height="match_parent"
 5               android:orientation="vertical"
 6               tools:context="com.xqx.superapp.app.Android5Activity">
 7 
 8     <Button
 9             android:text="添加一个数据"
10             android:layout_width="wrap_content"
11             android:layout_height="wrap_content"
12             android:onClick="btnAddItem"
13             />
14     <Button
15             android:text="删除第一个"
16             android:onClick="btnRemoveItem"
17             android:layout_width="wrap_content"
18             android:layout_height="wrap_content"/>
19     
20     <android.support.v7.widget.RecyclerView
21         android:id="@+id/recycle_view"
22         android:layout_width="match_parent"
23         android:layout_height="match_parent"
24         >
25     </android.support.v7.widget.RecyclerView>
26 
27 </LinearLayout>

菜单项布局,标准的上面图片,下面文字

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:gravity="center"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
        <ImageView
                android:id="@+id/item_icon"
                android:src="@mipmap/machao_moqi"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
        <TextView
                android:id="@+id/item_title"
                android:text="名称"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                />
</LinearLayout>

2.接下来就看Activity代码了

首先看成员变量,与ListView,GridView一样 标准三样, 控件,数据源,适配器

private List<String> data;          
private RecyclerView recyclerView;
private MyRecycleAdapter adapter;   //自定义适配器,继承RecyclerView.Adapter

接着我们必须要自定义一个ViewHolder,这个ViewHolder 必须要继承 RecyclerView.ViewHolder

注意RecyclerView不再提供onItemClick事件监听,所以需要我们自己手工写监听事件的方法

private static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        public ImageView imageView;
        public TextView textView;

        public ViewHolder(View itemView) {
            super(itemView);
            // 通常ViewHolder的构造,就是用于获取控件视图的
            imageView = (ImageView) itemView.findViewById(R.id.item_icon);
            textView = (TextView) itemView.findViewById(R.id.item_title);
            // TODO 后续处理点击事件的操作
            itemView.setOnClickListener(this);

        }
        @Override
        public void onClick(View v) {
            int position = getAdapterPosition();
            Context context = imageView.getContext();
            Toast.makeText(context,"显示第"+position+"个项",Toast.LENGTH_SHORT).show();
        }
    }

再让我们看自定义适配器,注意这里的参数是ViewHolder,这个ViewHodler是我们自己的,不要导入v7包下的ViewHolder,

之后要重写三个方法

private class MyRecycleAdapter extends RecyclerView.Adapter<ViewHolder>{
  

在自定义适配器MyRecycleAdapter中,首先要写一个构造方法,因为有数据源,所有构造方法里必然有List

private List<String> strings;
public MyRecycleAdapter(List<String> strings) {
     this.strings = strings;
}

然后就要重写三个方法了,

 1 @Override
 2 public int getItemCount() {
 3     int ret = 0;
 4     if (strings != null) {
 5         ret = strings.size();
 6      }
 7         return ret;
 8 }
 9 
10  @Override
11         public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
12             ViewHolder ret = null;
13             // 不需要检查是否复用,因为只要进入此方法,必然没有复用
14             // 因为RecyclerView 通过Holder检查复用
15             View v = LayoutInflater.from(Android5Activity.this).inflate(R.layout.item_recycler, viewGroup, false);
16             ret = new ViewHolder(v);
17             return ret;
18         }
19 
20 @Override
21         public void onBindViewHolder(ViewHolder viewHolder, int i) {
22             // 1.这里进行图片的加载
23             viewHolder.textView.setText(strings.get(i));
24             int resId = R.mipmap.ic_launcher;
25             int index = i%5;
26             switch (index){
27                 case 0:
28                     resId = R.mipmap.a11;
29                     break;
30                 case 1:
31                     resId = R.mipmap.a33;
32                     break;
33                 case 2:
34                     resId = R.mipmap.a22;
35                     break;
36             }
37             viewHolder.imageView.setImageResource(resId);
38         }

---------------------------------------------------------------------------------------------------------------

完成自定义适配器和自定义ViewHolder的代码 就要进行RecyclerView的使用了

首先 要了解  RecyclerView.LayoutManager 这个属性

用于进行一个布局的设置,可以设置显示模式,ListView或者GridView或者瀑布流

1.ListView显示模式

1 // 1.线性布局
2         LinearLayoutManager layoutManager =
3                 new LinearLayoutManager(this,   // 上下文
4                                         LinearLayout.VERTICAL,  //垂直布局,
5                                         false);

2.GridView显示模式

1 // 2.Grid布局
2         RecyclerView.LayoutManager layoutManager =
3                 new GridLayoutManager(this,
4                                       2,  // 每行显示item项数目
5                                       GridLayoutManager.HORIZONTAL, //水平排列
6                                       false
7                                       );

3.瀑布流显示模式

1 // 3.瀑布流
2         RecyclerView.LayoutManager layoutManager =
3                 new StaggeredGridLayoutManager(3,  // 每行显示的item项数目
4                         StaggeredGridLayoutManager.VERTICAL);  // 垂直排列

以上三种显示模式任意设置一种 就可以继续下面的代码

recyclerView.setLayoutManager(layoutManager);
        // 设置 RecyclerView的Adapter
        // 注意一定在设置了布局管理器之后调用
        adapter = new MyRecycleAdapter(data);
        recyclerView.setAdapter(adapter);

最后记得加上“添加一个数据”,“删除第一个数据”的按钮响应事件。

首先看一下以往我们对listview,gridview等等的删除某一项的操作

先在数据源中删除该位置的数据,然后刷新整个适配器,那么就可能会造成列表闪屏的问题,还有为了删除添加一个数据项而操作整个数据源的问题

public void btnAddItem(View view) {
        data.add(0,"Time:"+System.currentTimeMillis());
        adapter.notifyDataSetChanged();
    }
    public void btnRemoveItem(View view) {
        if (!data.isEmpty()) {
            data.remove(0);
        }
        adapter.notifyItemRemoved(0);
    }

 而RecyclerView为我们提供了一些新的实用的方法:

public void add(ViewModel item, int position) {
    items.add(position, item);    //数据源先添加该数据
    notifyItemInserted(position); //在某个位置刷新即可
}
 
public void remove(ViewModel item) {
    int position = items.indexOf(item);
    items.remove(position);      //数据源先删除该数据
    notifyItemRemoved(position); //在某个位置删除即可
}

完整代码:

  1 package com.xqx.superapp.app;
  2 
  3 import android.app.Activity;
  4 import android.content.Context;
  5 import android.support.v7.app.ActionBarActivity;
  6 import android.os.Bundle;
  7 import android.support.v7.widget.GridLayoutManager;
  8 import android.support.v7.widget.LinearLayoutManager;
  9 import android.support.v7.widget.RecyclerView;
 10 import android.support.v7.widget.StaggeredGridLayoutManager;
 11 import android.util.Log;
 12 import android.view.*;
 13 import android.widget.*;
 14 
 15 import java.util.LinkedList;
 16 import java.util.List;
 17 
 18 
 19 public class Android5Activity extends Activity {
 20 
 21     private List<String> data;
 22     private RecyclerView recyclerView;
 23     private MyRecycleAdapter adapter;
 24 
 25     @Override
 26     protected void onCreate(Bundle savedInstanceState) {
 27         super.onCreate(savedInstanceState);
 28         setContentView(R.layout.activity_android5);
 29         data = new LinkedList<String>();
 30         recyclerView = (RecyclerView) findViewById(R.id.recycle_view);
 31         // 设置布局管理器
 32         // 支持 单列线性排列,支持GridView模式,瀑布流模式
 33         // 1.线性布局
 34         LinearLayoutManager layoutManager =
 35                 new LinearLayoutManager(this,   // 上下文
 36                                         LinearLayout.VERTICAL,  //垂直布局,
 37                                         false);
 38 
 39 //        // 2.Grid布局
 40 //        RecyclerView.LayoutManager layoutManager =
 41 //                new GridLayoutManager(this,
 42 //                                      2,
 43 //                                      GridLayoutManager.HORIZONTAL,
 44 //                                      false
 45 //                                      );
 46 //
 47 //         // 3.瀑布流
 48 //        RecyclerView.LayoutManager layoutManager =
 49 //                new StaggeredGridLayoutManager(3,
 50 //                        StaggeredGridLayoutManager.VERTICAL);
 51         recyclerView.setLayoutManager(layoutManager);
 52         // 设置 RecyclerView的Adapter
 53         // 注意一定在设置了布局管理器之后调用
 54         adapter = new MyRecycleAdapter(data);
 55         recyclerView.setAdapter(adapter);
 56     }
 57 
 58     public void btnAddItem(View view) {
 59         data.add(0,"Time:"+System.currentTimeMillis());
 60         adapter.notifyDataSetChanged();
 61     }
 62 
 63     public void btnRemoveItem(View view) {
 64         if (!data.isEmpty()) {
 65             data.remove(0);
 66         }
 67         adapter.notifyItemRemoved(0);
 68     }
 69 
 70     /**
 71      * 继承RecyclerView.Adapter,用于显示数据
 72      * 需要定义并且使用 ViewHolder ,必须要使用
 73      */
 74     private class MyRecycleAdapter extends RecyclerView.Adapter<ViewHolder>{
 75         private List<String> strings;
 76         public MyRecycleAdapter(List<String> strings) {
 77             this.strings = strings;
 78         }
 79 
 80         @Override
 81         public int getItemCount() {
 82             int ret = 0;
 83             if (strings != null) {
 84                 ret = strings.size();
 85             }
 86             return ret;
 87         }
 88 
 89         @Override
 90         public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
 91             ViewHolder ret = null;
 92             // 不需要检查是否复用,因为只要进入此方法,必然没有复用
 93             // 因为RecyclerView 通过Holder检查复用
 94             View v = LayoutInflater.from(Android5Activity.this).inflate(R.layout.item_recycler, viewGroup, false);
 95             ret = new ViewHolder(v);
 96             return ret;
 97         }
 98 
 99         @Override
100         public void onBindViewHolder(ViewHolder viewHolder, int i) {
101             viewHolder.textView.setText(strings.get(i));
102             int resId = R.mipmap.ic_launcher;
103             int index = i%5;
104             switch (index){
105                 case 0:
106                     resId = R.mipmap.a11;
107                     break;
108                 case 1:
109                     resId = R.mipmap.a33;
110                     break;
111                 case 2:
112                     resId = R.mipmap.a22;
113                     break;
114             }
115             viewHolder.imageView.setImageResource(resId);
116         }
117     }
118 
119     /**
120      * 创建自己的ViewHolder ,必须要继承RecyclerView.ViewHolder
121      */
122     private static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
123         public ImageView imageView;
124         public TextView textView;
125 
126         public ViewHolder(View itemView) {
127             super(itemView);
128             // 通常ViewHolder的构造,就是用于获取控件视图的
129             imageView = (ImageView) itemView.findViewById(R.id.item_icon);
130             textView = (TextView) itemView.findViewById(R.id.item_title);
131             // TODO 后续处理点击事件的操作
132             itemView.setOnClickListener(this);
133 
134         }
135         @Override
136         public void onClick(View v) {
137             int position = getAdapterPosition();
138             Context context = imageView.getContext();
139             Toast.makeText(context,"显示第"+position+"个项",Toast.LENGTH_SHORT).show();
140         }
141     }
142 }

-------------------------------------------------------------------------------------------------------------

其他相关:

浅谈FloatingActionButton(悬浮按钮)

浅谈DrawerLayout(抽屉效果)

浅谈TabLayout(ViewPager+Tab联动)

浅谈GridLayout(网格布局)

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏潇涧技术专栏

Head First Android SwipeRefreshLayout

本文内容和代码参考自Implementing Swipe to Refresh, an Android Material Design UI Pattern,原...

1052
来自专栏Sorrower的专栏

界面无小事(二): 让RecyclerView展示更多不同视图

1462
来自专栏增长技术

App Intro相关

##How to use Add this to your build.gradle:

792
来自专栏Samego开发资源

图片自动轮播图

4006
来自专栏开发之途

Android 解析RecyclerView(3)——以更简单的方法实现带顶部View和底部View的RecyclerView

2143
来自专栏向治洪

ViewPager 实现 Galler 效果, 中间大图显示,两边小图展示

正常情况下, ViewPager 一页只能显示一项数据, 但是我们常常看到网上,特别是电视机顶盒的首页经常出现中间大图显示两端也都露出一点来,这种效果怎么实现呢...

7265
来自专栏Android开发经验

常用的代码片段,不断更新

1482
来自专栏向治洪

介绍几个好用的android自定义控件

首先看效果图, ? 看下这两个界面,第一个中用到了一个自定义的FlowRadioGroup,支持复合子控件,自定义布局; 第二个界面中看到了输入的数字 自...

3167
来自专栏developerHaoz 的安卓之旅

手把手教你从零开始做一个好看的 APP - Day four

本文为 手把手教你从零开始做一个好看的 APP - Day four ,如果想看该系列的其他文章,请点击以下连接

912
来自专栏Android 开发学习

ListView的一个典型crash cannot be cast to android.widget.AbsListView$LayoutParams1. 背景2. 为什么会出现crash3.

3093

扫码关注云+社区

领取腾讯云代金券