Android RecyclerView相关总结及ItemTouchHelper的使用

概述

RecyclerView出来已经很长时间了,关于其的介绍也非常的多.作为ListView的升级版,它更加强大和灵活.可以轻松的实现各种布局和动画.
见其名,知其意.RecyclerView 主要用于在有限窗口中展示大量数据集合的可复用的视图.
这里主要梳理一下Recyclerview的常用方法,示例Demo:BoBoMEe/AndroidDev

相关类

RecyclerView的灵活性,主要体现在各个类的职责分离上,RecyclerView本身并不负责子View的展示与布局,只负责子view的回收与复用.其他的比如,子View的布局,装饰及动画都交由其他类来处理.

RecyclerView相关类及其作用

用途
RecyclerView.ViewHolder装载子view数据的容器
RecyclerView.LayoutManager布局管理器,负责子View的布局
RecyclerView.Adapter适配器,负责处理数据与绑定视图
RecyclerView.ItemDecoration装饰子view,如分割线、偏移等
RecyclerView.ItemAnimator子view改变时的动画

基本使用

RecyclerView最简单的使用需要设置LayoutManagerAdapter,其他的都是可选项.简单使用流程可分为以下几步.

  • 引入
 compile 'com.android.support:recyclerview-v7:21.3.2'
<android.support.v7.widget.RecyclerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="@dimen/item_margin"
    android:clipToPadding="false"/>
  • 设置AdapterLayoutManager
RecyclerView mRecyclerView = (RecyclerView)findViewById(R.id.recycler_view);

mLinearLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLinearLayoutManager);

mRecyclerStringAdapter = new RecyclerStringAdapter(Datas.getDatas());
mRecyclerView.setAdapter(mRecyclerStringAdapter);

其中LinearLayoutManager代表线性显示.默认是方向为VERTICAL,LayoutManager抽象类有三个官方实现版本,分别是LinearLayoutManager(线性布局),GridLayoutManager(网格布局),StaggeredGridLayoutManager(瀑布流布局).

  • Adapter

不同于ListViewAdapter,Recyclerview的适配器强制使用ViewHolder模式.如下一个简单的Adapter实现

public class RecyclerStringAdapter extends RecyclerView.Adapter<RecyclerViewholder> {

  List<String> datas;
  public RecyclerStringAdapter(List<String> datas) {
    this.datas = datas;
  }

  @Override public void onBindViewHolder(RecyclerViewholder holder, int position) {
    holder.textView.setText(datas.get(position));
  }

  @Override public RecyclerViewholder onCreateViewHolder(ViewGroup parent, int viewType) {

   View view =
       LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item, parent, false);

   return new RecyclerViewholder(view);
 }

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

# RecyclerViewholder
public class RecyclerViewholder extends RecyclerView.ViewHolder {

  public TextView textView;

  public RecyclerViewholder(View itemView) {
    super(itemView);
    textView = (TextView) itemView.findViewById(R.id.text);
  }
}

其他用法

  • LayoutManager布局切换

我们知道LayoutManager主要负责子View的布局.通过设置不同的LayoutManager即可实现展现方式的改变.
如果不设置LayoutManager,数据将不会展现出来.

//gridview的列数为3,orientation = VERTICAL
mGridLayoutManager = new GridLayoutManager(this, 3);
mRecyclerView.setLayoutManager(mGridLayoutManager);
// 瀑布流的列数为3,orientation = VERTICAL
mStaggeredGridLayoutManager =
        new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(mStaggeredGridLayoutManager);
int orientation = mLinearLayoutManager.getOrientation();
mLinearLayoutManager.setOrientation(orientation == LinearLayoutManager.VERTICAL ? LinearLayoutManager.HORIZONTAL: LinearLayoutManager.VERTICAL);
  • LayoutManager常用方法
//返回当前第一个可见 Item 的 position
findFirstVisibleItemPosition() 
//返回当前第一个完全可见 Item 的 position
findFirstCompletelyVisibleItemPosition() 
//返回当前最后一个可见 Item 的 position
findLastVisibleItemPosition() 
//返回当前最后一个完全可见 Item 的 position.
findLastCompletelyVisibleItemPosition()  
  • ItemAnimatorItem动画

用于设置子view的添加、移动、删除的相关动画效果.官方默认提供了一个DefaultItemAnimator,如果我们没有设置ItemAnimator,则默认就是DefaultItemAnimator,Recyclerview.Adapter提供了notifyDataSetChanged()notifyItemInserted(index)notifyItemRemoved(position)notifyItemChanged(position)方法来刷新Recyclerview.这里可以看一下wasabeef/recyclerview-animators:实现了多种Recyclerview的Item动画,当然我们也可以通过继承DefaultItemAnimator来实现更加复杂的动画效果.

  • ItemDecorationItem装饰

通过mRecyclerView.addItemDecoration(new MarginDecoration(this));来给Item添加装饰,

ItemDecoration可以叠加,Recyclerview展示的时候会遍历所有的ItemDecoration并调用其绘制方法来对Item进行装饰.

ItemDecoration提供了三个方法用于定制装饰器:

// 在Item条目绘制之前调用,如果不是指offset则被Item的内容所遮挡
public void onDraw(Canvas c, RecyclerView parent);
// 在Item条目绘制之后调用,浮于Item之上
public void onDrawOver(Canvas c, RecyclerView parent);
// 计算并设置Item偏移量
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent);

Recyclerview多种布局

ListView中为了实现多种布局,我们需要重写Adapter中的 getItemViewTypegetViewTypeCount方法

而在Recyclerview中保留了getItemViewType方法,同时我们可以在onCreateViewHolder中根据不同的ViewType来创建不同的Holder

其中添加HeaderViewFooterwView的处理,同样也是通过ViewType来实现的,

接下来我们来看一下带有HeaderViewAdapter 的实现方式

public class RecyclerWithHeaderAdapter extends BaseRecyclerAdapter {

  private final View header;

  private static final int ITEM_VIEW_TYPE_HEADER = 0;
  private static final int ITEM_VIEW_TYPE_ITEM = 1;

  public boolean isHeader(int position) {
    return position == 0;
  }

  @Override public int getItemViewType(int position) {
    return isHeader(position) ? ITEM_VIEW_TYPE_HEADER : ITEM_VIEW_TYPE_ITEM;
  }

  public RecyclerWithHeaderAdapter(List<String> datas, View header) {
    super(datas);
    this.header = header;
  }

  @Override public RecyclerViewholder onCreateViewHolder(ViewGroup parent, int viewType) {

    if (viewType == ITEM_VIEW_TYPE_HEADER) {
      return new RecyclerViewholder(header);
    }

    return super.onCreateViewHolder(parent, viewType);
  }

  @Override public void onBindViewHolder(RecyclerViewholder holder, int position) {
    if (isHeader(position)) return;

    holder.textView.setText(datas.get(position - 1));
  }

  @Override public int getItemCount() {
    return datas.size() + 1;
  }
}

其中界面的主要代码

View header = LayoutInflater.from(this).inflate(R.layout.recycler_header, mRecyclerView, false);
    mRecyclerWithHeaderAdapter = new RecyclerWithHeaderAdapter(Datas.getDatas(), header);
    mRecyclerView.setAdapter(mRecyclerWithHeaderAdapter);

    mGridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
      @Override public int getSpanSize(int position) {
        return mRecyclerWithHeaderAdapter.isHeader(position) ? mGridLayoutManager.getSpanCount() : 1;
      }
    });

在网格布局中,依靠了GridLayoutManager#setSpanSizeLookup方法来设置每个Item占多少个span,

如果是在瀑布流布局中,则可以通过给StaggeredGridLayoutManager.LayoutParams设置setFullSpan(true);来占满一行.
参考自: RecyclerView添加Header的正确方式

ItemTouchHelper

用于Recyclerview的触摸辅助操作,比如选中,移动,删除等事件的监听.
这里可以看一下: 可拖拽的RecyclerView,通过跟踪代码我们可以看到,ItemTouchHelper内部
主要是通过GestureDetectorCompat来处理触摸事件,并通过给Recyclerview设置OnItemTouchListener来实现效果
但是遗憾的是其中只 实现了onLongPress的监听.但是为我们设置Recyclerview的Item监听提供了一种新的思路

//ItemTouchHelper#ItemTouchHelperGestureListener
private class ItemTouchHelperGestureListener extends GestureDetector.SimpleOnGestureListener {

    @Override
    public boolean onDown(MotionEvent e) {
        return true;
    }

    @Override
    public void onLongPress(MotionEvent e) {
      //...
    }
}

通过ItemTouchHelper实现RecyclerviewClick,LongClick,Select,Swipe,Drag等效果,
主要通过一个叫做ItemTouchHelper.Callback的类,示例:RvItemTouchHelperCallback

Recyclerview 选中模式

遗憾的是Recyclerview并不像Listview那样提供selectMode,但是在我们最初不适用selectMode的时候,我们是否采用过一种通过刷新Adapter来实现的方式呢
Recyclerview中要实现选中模式,我们当然也要从Adapter下手,这里可以看一下Multi-Selection Mode for RecyclerView
其中的核心代码

 private SparseBooleanArray mSelectedItems;

 public void switchSelectedState(int position) {
       if (mSelectedItems.get(position)) {       // item has been selected, de-select it.
           mSelectedItems.delete(position);
       } else {
           mSelectedItems.put(position, true);
       }
       notifyItemChanged(position);
   }

   public void clearSelectedState() {
       List<Integer> selection = getSelectedItems();
       mSelectedItems.clear();
       for (Integer i : selection) {
           notifyItemChanged(position);
       }
   }

可以看到作者也是通过在Adapter中维护一个选中的集合来实现Recyclerview的选中模式的,
最后,这里是从 其他项目中 收集的 Recyclerview 好用的 Utils :RecyclerViewHelper

总结

Recyclerview不仅在灵活度和扩展性上都较AbsListView好,在项目中也得到了大量的使用,也还有大量的未知方法等着去实践,
比如RecyclerviewScroll操作,RecycledViewPool.Recyclerview的上下拉刷新,
自定义LayoutManageritemDecorationitemAnimator等待

参考:
Android RecyclerView 使用完全解析 体验艺术般的控件
可拖拽的RecyclerView
Multi-Selection Mode for RecyclerView
Using the RecyclerView
RecyclerView添加Header的正确方式

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值