Android笔记—UI-RecyclerView


资料来源如下

  • 第一行代码(第二版)
  • RecyclerView使用详解—六和敬
  • RecyclerView使用介绍— Jin Yudong
  • Android RecyclerView 使用完全解析 体验艺术般的控件—鸿洋_
  • 创建列表与卡片—Android Developer

编程环境

  • Android Studio 2.2.3

导语

  • RecyclerView内容较ListView更多,初期只能更新一些基础内容,高级的用法随时更新,长期跟进

简介

  • RecyclerView是用于取代ListView的组件,第一次出现是在2014年google I/O大会,内置在是Android L及以上版本的SDK中。
  • 对比与ListView,RecyclerView弥补了ListView中的效率问题,同时支持更多的显示效果,代码逻辑更为清晰

基本使用步骤


  • RecyclerView定义在support库中,使用RecyclerView之前必须在添加依赖
  • build.gradle中添加
    compile 'com.android.support:recyclerview-v7:25.1.0'

  • RecyclerView项目结构如下:
    RecyclerView.png

  • 要使用RecyclerView,需要指定一个Adapter适配器和一个LayoutManager布局管理器

  • Adapter适配器:作用与ListView中使用的Adapter相同,都是将数据与对应item的界面进行绑定
    所不同的是:RecyclerView中适配器必须继承自RecyclerView.Adapter,且 强制使用了ViewHolder

  • LayoutManager布局管理器:每一个item如何进行排列,何时展示和隐藏。
    重用View时,LayoutManager会向Adapter适配器请求新的数据替换旧的数据,避免了View的冗余和频繁调用findViewById

    LayoutManager的引入 使得各种布局排列编写,变的格外容易,这也是RecyclerView优于ListView的一个地方

  • 目前RecyclerView 内置3种LayoutManager:

    • LinearLayoutManager 横向/竖向布局
    • GridLayoutManager 网格布局
    • StaggeredGridLayoutManager 瀑布流布局
  • MainActivity中 RecyclerView 设置

    1. 创建RecyclerView对象
      RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycle_view);

    2. 设置LayoutManager显示规则

    3. 设置适配器
      recyclerview.setAdapter(adapter);

简单实例

由一个简单的实例+详细分析

  • 添加依赖
    打开app/build.gradle文件,在dependencies闭包下添加依赖库
    版本与你工程的com.android.support:appcompat-v7:25.1.0版本对应

    1
    compile 'com.android.support:recyclerview-v7:25.1.0'

    之后AndroidStudio会开始同步

  • 添加RecyclerView到xml文件,基本与ListView一致,不过RecyclerView并非内置在SDK中,这里需要写出完整的包路径

    1
    2
    3
    4
    5
    <android.support.v7.widget.RecyclerView
    android:id="@+id/recycle_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    />
  • 要展示的依旧是水果+图片形式,
    图片资源在第一行代码第二版源码 /chapter3/ListViewTest\app\src\main\res\drawable-hdpi下,同时将Fruit类和fruit_item.xml一并复制,这里给出两者源码,不再加分析_

    • Fruit类
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      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;
      }
      }
    • fruit_item.xml _
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      <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>
  • 准备RecyclerView适配器,适配器需要继承自 RecyclerView.Adapter,将泛型指定为 .ViewHolder,(ViewHolder为在适配器的一个内部类),并重写3个方法

    1
    2
    3
    public ViewHolder onCreateViewHolder(ViewGroup parent,int viewType)//创建返回ViewHolder实例
    public void onBindViewHolder(ViewHolder holder,int pisition)//数据与界面绑定
    public int getItemCount() // 返回数据的数量

    新建 FruitAdapter 继承自 RecyclerView.Adapter

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
      //继承自RecyclerView.Adapter,泛型为  FruitAdapter .ViewHolder
    public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {
    //私有Fruit列表
    private List<Fruit> mFruitList;

    //新建内部类ViewHolder继承自RecyclerView.ViewHolde有每个Item的的所有界面元素
    static class ViewHolder extends RecyclerView.ViewHolder{
    ImageView fruitImage;
    TextView fruitName;
    //ViewHolder构造函数,传入View,通常为RecyclerView子项的外层布局(本例为fruit_item.xml)
    public ViewHolder(View view){
    super(view);
    //findViewById获取 Image/Name实例
    fruitImage = (ImageView)view.findViewById(R.id.fruit_image);
    fruitName = (TextView)view.findViewById(R.id.fruit_name);
    }
    }

    //FruitAdapter构造函数,将数据源传入全局变量mFruitList
    public FruitAdapter(List<Fruit>fruitList){
    mFruitList = fruitList;
    }

    @Override
    //创建ViewHolder实例
    public ViewHolder onCreateViewHolder(ViewGroup parent,int viewType){
    //加载布局文件
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item,parent,false);
    //调用ViewHolder构造函数
    ViewHolder holder = new ViewHolder(view);
    //返回ViewHolder实例
    return holder;
    }

    @Override
    //对 RecyclerView子项进行赋值,有新的子项进入屏幕显示范围时调用
    public void onBindViewHolder(ViewHolder holder,int pisition){
    Fruit fruit = mFruitList.get(pisition);
    holder.fruitImage.setImageResource(fruit.getImageId());
    holder.fruitName.setText(fruit.getName());
    }

    @Override
    //返回 RecyclerView子项数量
    public int getItemCount(){
    return mFruitList.size();
    }

    }
  • MainActivity中使用RecyclerView

    • 创建RecyclerView对象

    • 设置LayoutManager显示规则(默认竖向滚动)

    • 设置适配器

    代码如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
     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);

    //初始化Fruits数据
    initFruits();
    //获取RecyclerView实例
    RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycle_view);

    //创建LinearLayoutManager,并设置入recyclerView
    LinearLayoutManager layoutManager = new LinearLayoutManager(this);
    recyclerView.setLayoutManager(layoutManager);

    //新建适配器,并传入
    FruitAdapter adapter = new FruitAdapter(fruitList);
    recyclerView.setAdapter(adapter);
    }

    //初始化Fruits类
    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);
    }
    }
    }
  • 这样最简单的 RecyclerView 就搭建完了效果如下
    ScreenShot_20161216105246.png

  • 代码比ListView稍多,但是逻辑比较清晰。

横向/瀑布流/网格布局

  • 只需要设置相应LayoutManager即可 /手动滑稽

    横向

  • 在 LinearLayoutManager 中修改几行代码即可

  • 修改 LinearLayoutManager 代码,添加一行,搞定!

    1
    layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
  • 当然需要简单修改一下item的布局文件,LinearLayout改为垂直排列,宽度固定100dp,图片/文字居中
    效果如下
    ScreenShot_20161216105723.png

瀑布流

  • 这需要 StaggeredGridLayoutManager 布局管理器,可以 竖向/横向 滚动

  • 代码如下

    1
    2
    //瀑布流布局,3行,竖向
    StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
  • 调整布局文件,效果如下
    ScreenShot_20161216215538.png

网格

  • 这需要 GridLayoutManager 布局管理器
  • 代码如下
    1
    2
    //网格布局,两行
    GridLayoutManager layoutManager = new GridLayoutManager(this,3);
  • 调整布局文件后,效果如下
    ScreenShot_20161216220321.png

注册点击事件

  • RecyclerView 中并没有提供注册监听器的方法,需要子项View自行注册
  • 部分代码如下
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
      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);
    }
    }

    @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(), "you clicked view " + fruit.getName(), Toast.LENGTH_SHORT).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(), "you clicked image " + fruit.getName(), Toast.LENGTH_SHORT).show();
    }
    });
    return holder;
    }