1- 简单使用
1.1依赖
根据你studio的buildToolsVersion来写(不然编译不通过)。
例如我的buildToolsVersion "25.0.0"
我会这样写(很难找到确定的版本号)(alt+enter)
compile 'com.android.support:recyclerview-v7:25.+'
1.2 设置布局管理器—显示出来的布局风格
有三种风格
//首先设置LayoutManager:控制RecyclerView如何显示布局,系统提供3个布局管理器:
LinearLayoutManager://线性布局,有横向和竖直方向显示
GridLayoutManager://网格布局,有横向和竖直方向显示
StaggeredGridLayoutManager: //瀑布流布局,有横向和竖直方向显示
单列列表
//首先设置布局管理器,就是显示出来的布局的样子,单列列表
recyclerView.setLayoutManager(new LinearLayoutManager(this));
//参数2是否反转布局
recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
多列列表—参数2列数
//多列的规则列表
recyclerView.setLayoutManager(new GridLayoutManager(this, 3));
//参数2是否反转布局
recyclerView.setLayoutManager(new GridLayoutManager(this, 3,GridLayoutManager.HORIZONTAL, false));
瀑布流--参数2列数
//多列的不规则的列表,也就是俗称瀑布流效果
recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));
1.3 展示数据设置adapter
recyclerView.setAdapter(new MyAdapter());
条目分割线
//条目分割线
recyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));
**ViewHolder **
class MyHolder extends RecyclerView.ViewHolder {
@BindView(R.id.iv_image)
ImageView ivImage;
@BindView(R.id.tv_text)
TextView tvText;
@BindView(R.id.cardVIew)
CardView cardVIew;
public MyHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
MyAdapter
//泛型 viewholder类型
class MyAdapter extends RecyclerView.Adapter<MyHolder> {
//重写onCreateViewHolder--返回一个ViewHolder即可
@Override
public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = View.inflate(parent.getContext(), R.layout.adapter_recycler, null);
return new MyHolder(view);
}
//重写onBindViewHolder设置数据的
@Override
public void onBindViewHolder(MyHolder holder, int position) {
holder.ivImage.setImageResource(Constant.images.get(position));
holder.tvText.setText("数据 - " + position);
}
//重写getItemCount()返回条目数量
@Override
public int getItemCount() {
return Constant.images.size();
}
}
条目点击事件
设置点击事件,由于RecyclerView没有setOnItemClickListener,只能在Adapter中给View设置Click事件
//设置点击事件
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(RecyclerViewAcitvity.this, "点击的是:" + position, Toast.LENGTH_SHORT).show();
}
});
1.4 给条目添加动画
因为在条目中添加动画—因此在adapter中写
public class AnimateAdapter<T> extends CommonAdapter<T> {
public AnimateAdapter(Context context, int layoutId, List<T> datas) {
super(context, layoutId, datas);
}
@Override
protected void convert(ViewHolder holder, T t, int position) {
//给holder的itemView添加动画
animateHolder(holder);
}
protected void animateHolder(ViewHolder holder) {
//先变小
holder.itemView.setScaleX(0.5f);
holder.itemView.setScaleY(0.5f);
holder.itemView.setRotationX(180);
//再变大—添加缩放
ViewCompat.animate(holder.itemView).rotationX(0)
.scaleX(1f).scaleY(1f)
.setDuration(1000)
.setStartDelay(100)
.setInterpolator(new OvershootInterpolator())
.start();
}
}
2 LayoutManager实现卡片层叠布局
- 1-自定义LayoutManager:extends RecyclerView.LayoutManager
- 2-重写:onLayoutChildren: layout出我们想要的view即可
- 3-设置给recyclerview使用
public class OverLayCardLayoutManager extends RecyclerView.LayoutManager {
private static final String TAG = "swipecard";
@Override
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
Log.e(TAG, "onLayoutChildren() called with: recycler = [" + recycler + "], state = [" + state + "]");
//轻量级回收 界面上的所有View(如果有view),并且稍后会用到这些view,用detach回收
//如果是回收以后,稍后不会立刻用到,用recycle回收removeAndRecycleAllViews(recycler);
detachAndScrapAttachedViews(recycler);
//获取itemCunt
int itemCount = getItemCount();
if (itemCount < 1) {
return;
}
//top-3View的position
int bottomPosition;
//边界处理
if (itemCount < CardConfig.MAX_SHOW_COUNT) {
bottomPosition = 0;
} else {
bottomPosition = itemCount - CardConfig.MAX_SHOW_COUNT;
}
//从可见的最底层View开始layout,依次层叠上去
//循环遍历我们需要的子view
for (int position = bottomPosition; position < itemCount; position++) {
//所有LayoutManager需要的子view,通过recycler获取
View view = recycler.getViewForPosition(position);
//添加到rv里面
addView(view);
//measure
measureChildWithMargins(view, 0, 0);
//measure View 水平居中
//计算x方向和y方向
int widthSpace = getWidth() - getDecoratedMeasuredWidth(view);
int heightSpace = getHeight() - getDecoratedMeasuredHeight(view);
layoutDecoratedWithMargins(view, widthSpace / 2, heightSpace / 2,
widthSpace / 2 + getDecoratedMeasuredWidth(view),
heightSpace / 2 + getDecoratedMeasuredHeight(view));
/**
* TopView的Scale 为1,translationY 0
* 每一级Scale相差0.05f,translationY相差7dp左右
*
* 观察人人影视的UI,拖动时,topView被拖动,Scale不变,一直为1.
* top-1View 的Scale慢慢变化至1,translation也慢慢恢复0
* top-2View的Scale慢慢变化至 top-1View的Scale,translation 也慢慢变化只top-1View的translation
* top-3View的Scale要变化,translation岿然不动
*/
//第几层,举例子,count =7, 最后一个TopView(6)是第0层,
int level = itemCount - position - 1;
//除了顶层不需要缩小和位移
if (level > 0 /*&& level < mShowCount - 1*/) {
//每一层都需要X方向的缩小(值1表示不应用缩放)(position大 level小 scale大)
view.setScaleX(1 - CardConfig.SCALE_GAP * level);
//前N层,依次向下位移和Y方向的缩小
if (level < CardConfig.MAX_SHOW_COUNT - 1) {
//top position大 level小 Translation小(下移)
view.setTranslationY(CardConfig.TRANS_Y_GAP * level);
view.setScaleY(1 - CardConfig.SCALE_GAP * level);
} else {//第N层在 向下位移和Y方向的缩小的成都与 N-1层保持一致
view.setTranslationY(CardConfig.TRANS_Y_GAP * (level - 1));
view.setScaleY(1 - CardConfig.SCALE_GAP * (level - 1));
}
}
}
}
}
mRv.setLayoutManager(new OverLayCardLayoutManager());
3 ItemTouchHelper实现炫酷动画
ItemTouchHelper--介绍
- 这货是一个工具类,为RecyclerView扩展滑动消失(删除)和drag & drop效果的。
- 它需要和RecyclerView、Callback 一起工作。Callback 类里定义了 允许哪些交互,并且会接收到对应的交互事件
- 根据你需要哪种功能(滑动消失(删除)和drag & drop),你需要重写
- Callback#onMove(RecyclerView, ViewHolder, ViewHolder)—–drag & drop
- Callback#onSwiped(ViewHolder, int) 方法。 —–滑动消失(删除)
ItemTouchHelper使用
- 总结一下入门级用法如下,三个步骤:
- 1 定义一个Callback:ItemTouchHelper.Callback callback = new ItemTouchHelper.SimpleCallback(int,int),这两个int分别代表要 监听哪几个方向上的拖拽、滑动事件。 常用:ItemTouchHelper.DOWN | ItemTouchHelper.UP | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT
- 2 将Callback传给ItemTouchHelper:ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);
- 3 关联ItemTouchHelper和RecyclerView:itemTouchHelper.attachToRecyclerView(mRv)
- 4 ItemTouchHelper还负责在其他孩子被拖动后绘制孩子,因此还可以在onChildDraw中进行拖拽时子view的效果
- ItemTouchHelper就会自动帮我们完成 滑动消失(删除)和drag & drop 的功能。
撸码
public class RenRenCallback extends ItemTouchHelper.SimpleCallback {
protected RecyclerView mRv;
protected List mDatas;
protected RecyclerView.Adapter mAdapter;
//前一个int是拖拽-后一个int是滑动
//需要的是滑动消失(删除) ,所以我们的Callback不需要关注onMove()方法。
public RenRenCallback(RecyclerView rv, RecyclerView.Adapter adapter, List datas) {
this(0,
ItemTouchHelper.DOWN | ItemTouchHelper.UP | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT,
rv, adapter, datas);
}
public RenRenCallback(int dragDirs, int swipeDirs
, RecyclerView rv, RecyclerView.Adapter adapter, List datas) {
super(dragDirs, swipeDirs);
mRv = rv;
mAdapter = adapter;
mDatas = datas;
}
//水平方向是否可以被回收掉的阈值
public float getThreshold(RecyclerView.ViewHolder viewHolder) {
//2016 12 26 考虑 探探垂直上下方向滑动,不删除卡片,这里参照源码写死0.5f
return mRv.getWidth() * /*getSwipeThreshold(viewHolder)*/ 0.5f;
}
//在drag & drop 会回调
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
//滑动消失 swipe dismiss 回调 滑动删除动作已经发生后回调的
//我们先滑动卡片,然后松手,此时ItemTouchHelper判断我们的手势是删除手势,会自动对这个卡片执行丢出屏幕外的动画,同时回调onSwiped()方法。
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
//★实现循环的要点
//利用当前被删除的View的ViewHolder拿到Position--删除数据集中对应Position的数据源
Object remove = mDatas.remove(viewHolder.getLayoutPosition());
//同时将该数据源插入数据集中的首位,第0位
mDatas.add(0, remove);
//调用notifyDataSetChanged(),通知列表刷新
//使用notifyDataSetChanged()原因:即ItemTouchHelper实现的滑动删除,其实只是隐藏了这个滑动的View。并不是真的删除了。
mAdapter.notifyDataSetChanged();
//notifyDataSetChanged()会回调LayoutManager.onLayoutChildren()这个函数,
// 而在这个函数中,我们会重新布局,即真正的移除(不再layout)滑动掉的View,同时会补充进新的最底层的View。
}
//ItemTouchHelper还负责在其他孩子被拖动后绘制孩子。
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
//先根据滑动的dxdy 算出现在动画的比例系数fraction
double swipValue = Math.sqrt(dX * dX + dY * dY);
double fraction = swipValue / getThreshold(viewHolder);
//边界修正 最大为1
if (fraction > 1) {
fraction = 1;
}
//对每个ChildView进行缩放 位移
int childCount = recyclerView.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = recyclerView.getChildAt(i);
//第几层,举例子,count =7, 最后一个TopView(6)是第0层,
int level = childCount - i - 1;
if (level > 0) {
child.setScaleX((float) (1 - SCALE_GAP * level + fraction * SCALE_GAP));
if (level < MAX_SHOW_COUNT - 1) {
child.setScaleY((float) (1 - SCALE_GAP * level + fraction * SCALE_GAP));
child.setTranslationY((float) (TRANS_Y_GAP * level - fraction * TRANS_Y_GAP));
} else {
//child.setTranslationY((float) (mTranslationYGap * (level - 1) - fraction * mTranslationYGap));
}
}
}
}
}
//step 1
ItemTouchHelper.Callback callback = new RenRenCallback(mRv, mAdapter, mDatas);
//step 2
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);
//step 3
itemTouchHelper.attachToRecyclerView(mRv);
4 实现插入、删除、更新对应的item
通过RecyclerView.Adapter的各notifyItem实现
- 4.1 notifyDataSetChanged ()
通知数据发生改变, LayoutManagers将被迫完全重新绑定并重新布局所有可见的视图。
- 4.2 notifyItemChanged (int position, Object payload)
项目更改事件
通知该位置处的item其对应的数据发生了改变。
position 已更改的项目的位置
payload 可选参数,使用null标识“完整”更新
- 4.3 notifyItemChanged (int position)
通知position位置上的item已改变(该位置的数据该更新了),相当于调用notifyItemChanged(position, null);.
position 已更改的项目的位置
- 4.4 notifyItemInserted (int position)
结构性变化事件,反映在position已被新插入,之前在位置的item现在位于position+1
position 新插入的项目在数据集中的位置
- 4.5 notifyItemMoved (int fromPosition, int toPosition)
结构行变化事件,在fromPosition上展示的item已被移动到toPosition
fromPosition 该item的以前位置。
toPosition 该item的新位置。
- 4.6 notifyItemRangeChanged (int positionStart, int itemCount, Object payload)
item更改事件不是结构更改事件。从positionStart开始的itemCount个项目已经改变
positionStart 第一项已更改的位置
itemCount 已更改的项目数量
payload 可选参数,使用null标识“完整”更新
- 4.7 notifyItemRangeChanged (int positionStart, int itemCount)
item更改事件不是结构更改事件。从positionStart开始的itemCount个项目已经改变。相当于notifyItemRangeChanged(position, itemCount, null);.
positionStart 第一项已更改的位置
itemCount 已更改的项目数量
- 4.8 notifyItemRangeInserted (int positionStart, int itemCount)
从positionStart开始的当前反映的itemCount项目已被新插入。 现在可以在位置positionStart + itemCount处找到之前位于positionStart和之后的项目。
positionStart 插入的第一个项目的位置
itemCount 插入的项目数量
- 4.9 notifyItemRangeRemoved (int positionStart, int itemCount)
结构性变化事件
以前位于positionStart的itemCount项目已从数据集中移除。 之前位于positionStart + itemCount之后的项目现在可以在oldPosition - itemCount中找到。
positionStart 已删除的第一个项目的前一个位置
itemCount 从数据集中删除的项目数量
- 4.10 notifyItemRemoved (int position)
结构性变化事件
以前位于该position的item已从数据集中移除。 先前位于位置和之后的物品现在可以在oldPosition - 1处找到。
position 已删除项目的位置