概述
在android开发中我们不可避免的会用到Recyclerview,用以替代之前的ListView,GridView,Gallery等.它是support:recyclerview-v7中提供的控件,最低兼容到android 3.0版本.之前listview难以实现或者不能实现的效果,它都可以实现或者轻松实现.
1.那么它有哪些优势呢?
总结也就一句话:高类聚低耦合.RecyclerView已经标准化ViewHolder,我们自定义的ViewHoler需要继承 RecyclerView.ViewHolder,然后在构造方法中初始化控件.
2.如何添加依赖?
- implementation 'com.android.support:recyclerview-v7:26.1.0'
如果只是用到recyclerview控件优先选用此依赖方式
- implementation 'com.android.support:design:26.1.0'
通过添加MD的disign包方式使用该控件,内部包含多种MD控件如:SnakeBar,
3.有哪些常用操作?
- LayoutManager,布局管理器,控制其显示的方式。
- ItemDecoration,控制Item间的间隔(允许绘制)。
- ItemAnimator,控制Item增删的动画。
使用
recyclerview的布局管理器有三种分别是线性布局管理器(LinearLayoutManager);表格布局管理器(GridLayoutManager);瀑布流布局管理器(StaggeredGridLayoutManager)。这个不做详细介绍。简单上一下代码。
//设置为线性管理器
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
//设置为表格管理器
mRecyclerView.setLayoutManager(new GridLayoutManager(this,3));
//瀑布流管理器
StaggeredGridLayoutManager manager = new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(manager);
//设置item增加删除动画
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
//给item增加自带分割线
mRecyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));
关于RecyclerView设置分割线和增加删除动画我们这里使用的是默认你都可以自定义,这个无所谓。
1.item的监听
不知道为啥recycleerview没有提供监听方法,这就要我们手动写相关代码了,这个实现方式一般有两种。前者是通过对Recyclerview触摸的监听,后者是自定义接口实现接口回调。后者相对简单,在我们的adapter中我们来搞一下:
item的监听 方式一
private OnItemClickLitener mOnItemClickLitener;
public interface OnItemClickLitener
{
void onItemClick(View view, int position);
void onItemLongClick(View view , int position);
}
public void setOnItemClickLitener(OnItemClickLitener OnItemClickLitener)
{
this.mOnItemClickLitener = OnItemClickLitener;
}
然后设置监听回调:
@Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
holder.tvName.setText(mArrayList.get(position).name);
holder.tvSex.setText(mArrayList.get(position).sex);
holder.tvAge.setText(mArrayList.get(position).age + "");
// 如果设置了回调,则设置点击事件
if (mOnItemClickLitener != null) {
holder.LinearItem.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int pos = holder.getLayoutPosition();
mOnItemClickLitener.onItemClick(holder.itemView, pos);
}
});
holder.LinearItem.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
int pos = holder.getLayoutPosition();
mOnItemClickLitener.onItemLongClick(holder.itemView, pos);
return false;
}
});
}
}
在写一个增加和减少item的方法:
public void addItem(int position) {
RecyclerViewBean mRecyclerViewBean =new RecyclerViewBean("增加用户"+position,100,"nan");
mArrayList.add(position, mRecyclerViewBean);
notifyItemInserted(position);
}
public void removeItem(int position) {
mArrayList.remove(position);
notifyItemRemoved(position);
}
设置adaper监听:
mRecyclerViewAdapter.setOnItemClickLitener(new RecyclerViewAdapter.OnItemClickLitener() {
@Override
public void onItemClick(View view, int position) {
mRecyclerViewAdapter.addItem(position);
}
@Override
public void onItemLongClick(View view, int position) {
mRecyclerViewAdapter.removeItem(position);
}
});
item的监听 方式二(对recyclerview触摸实现监听)
这个相对有一点难度,在这个之前我们要先来了解一个手势识别类----》GestureDetectorCompat
如果你不了解GestureDetectorCompat那么你一定知道onTouchEvnet,我们刚开始都是通过View.OnTouchListener内部接口,通过重写他的[onTouch]方法,获取Action来判断move,up,down动作,如下:
mRecyclerView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = MotionEventCompat.getActionMasked(event);
switch(action) {
case (MotionEvent.ACTION_DOWN) :
Log.d(DEBUG_TAG,"Action was DOWN");
return true;
case (MotionEvent.ACTION_MOVE) :
Log.d(DEBUG_TAG,"Action was MOVE");
return true;
case (MotionEvent.ACTION_UP) :
Log.d(DEBUG_TAG,"Action was UP");
return true;
default :
return super.onTouchEvent(event);
}
});
不陌生吧,但是这个监听只能应对一些简单的操作,如果是一些比较复杂的,比如:根据用户触摸的轨迹去判断是什么手势就显得吃力了,所以Android sdk给我们提供了GestureDetectorCompat(Gesture:手势Detector:识别)类,更高效。
GestureDetectorCompat类是GestureDetector的替代,它的创建方式有两种,我们选第一种方式
它是V4包下的。这不是重点,重点是我们怎么用它,感兴趣的小伙伴自行百度。
先来说一下我们的思路:
给Recyclerview设置添加OnItemTouchListener监听重写其方法,然后创建GestureDetectorCompat对象,通过一个手势探测器 GestureDetectorCompat 来探测屏幕事件,然后通过手势监听器 SimpleOnGestureListener 来识别具体事件种类,对应回调,算了上代码吧
RecyclerView的addOnItemTouchListener监听
ItemTouchListener这个类提出来单独使用,可以减少每个adapter中都定义一个接口回调,优化性能还高大上
2.RecyclerView之ItemDecoration
2.1.itemDecoration 简单使用
2.1.1 itemDecoration 简单使用针对LinearLayoutManager
mRecyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));
大家都注意到我们给recyclerview设置的这个属性了吧,这个属性就是使用其默认的ItemDecoration, DividerItemDecoration 继承自ItemDecoration。ok,我们试试如果自定义一个分割线。看一下DividerItemDecoration的setDrawable()方法。
/**
* Sets the {@link Drawable} for this divider.
*
* @param drawable Drawable that should be used as a divider.
*/
public void setDrawable(@NonNull Drawable drawable) {
if (drawable == null) {
throw new IllegalArgumentException("Drawable cannot be null.");
}
mDivider = drawable;
}
明白了吧,先自定义一个drawable文件,如下:
给RecyclerView添加代码,如下:
2.1.2 itemDecoration 简单使用针对GridLayoutManager和StaggeredGridLayout
因为GridLayoutManager和StaggeredGridLayout的原理和方法差异不大, 我们就统一写一个了。
1.如果只是想简单实现我们可以在adapter的onCreateViewHolder()方法中设置View,如图:
2.2 如果想来一个稍微有难度的,可以尝试自定义一个ItemDecoration,那么就要 extends RecyclerView.ItemDecoration重写两个方法(其实一般有三个,我们这里用不到其中的一个onDrawOver):第一个getItemOffsets()此方法是针对每一个 ItemView,实际上RecyclerView 中的 ItemView 外面会包裹着一个矩形(outRect)。当outRect的左,右,上,下的内容都为0时,itemview和ontRect重叠你感觉只有一个item.类似:
其目的是控制矩形(outRect)与 ItemView的间隔,部分代码如下:
第二个方法:onDraw(),该方法配合前面的 getItemOffsets() 一起使用,在outRect矩形 与 ItemView的间隔区域 绘制内容,也就是在itemview的下面绘制了一个矩形的分割线,部分代码如下:
最后一步:给recyclerview设置自定义的分割线:
3.RecyclerView之实现滑动删除拖拽排序(首个可以固定)
3.1实现RecyclerView的滑动删除拖拽排序
滑动删除和拖拽必须用到ItemTouchHelper ,我们看它如何使用:
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.Callback());
itemTouchHelper.attachToRecyclerView(mRecyclerView);
其创建的对象过程中要传一个ItemTouchHelper.CallBack(),它是ItemTouchHelper在拖拽中需要回调的方法,我们只需要在其对应返回的回调方法中处理自己的逻辑就好了,先看extends它需要重写的三个方法及作用。
针对getMovementFlags()方法如果是线性布局管理器有两个方向:上,下。但如果是网格布局管理器则有四个方向上,下,左,右,所以其方法要做判断是那种管理器,代码如下:
onMove()方法中的操作,注释都很明了,看不懂转行吧
这两个方法重写完,已经可以实现拖拽效果了,但为了美观我们要添加一个拖拽的背景,这就要用到另外两个方法:onSelectedChanged()和clearView(),代码如下:
然后就实现拖拽功能了
ItemTouchHelper itemTouchHelper
= new ItemTouchHelper(new RecyclerItemTouchHelperCallBack(mRecyclerViewAdapter));
itemTouchHelper.attachToRecyclerView(mRecyclerView);
再然后我们使用第三个方法来实现滑动删除。
别忘了变动之前的getMovementFlags()。
这样我们就实现了滑动删除和拖拽移动功能,但别高兴太早,这代码仍然存在问题,你正常来讲网格布局应该不具备滑动删除才对,这怎么解决呢?通过有参构造来设置一个变量,在重写一个isItemViewSwipeEnabled()返回该boolean类型的值控制是否具备滑动删除即可。如图:
这样就是实现线性布局管理器和网格布局管理器区分对待,即:线性布局管理器拥有滑动删除和拖拽而网格布局管理器只拥有拖拽功能。
3.2实现首item固定功能
既然实现了item的拖拽和删除那么,首个固定就很简单了,我们继续在有参构造里添加一个boolean类型的变变量控制是否首个item固定,然后重写一个方法,如图:
所有item都被固定,然后
至此,首个item固定也就完成了。
4.RecyclerView之实现自定义动画
大家都看到了我们之前使用的是系统给我们提供的自带动画mRecyclerView.setItemAnimator(new DefaultItemAnimator());
DafaultItemAnimator继承的是抽象类SimpleItemAnimator,SimpleItemAnimator主要对动画内部实现进行封装,通过抽象让我们更只关注于更具体的操作,我们定义一个类继承SimpleItemAnimator,然后里面主要有几个需要重写的方法。
- void runPendingAnimations():当有动画需要执行时调用。
- boolean isRunning():返回当前是否有动画正在运行。
- boolean animateAdd():添加元素时调用,通常返回true。
- boolean animateRemove():移除数据时调用。
- boolean animateMove():列表项位置移动时调用。
- boolean animateChange():列表项数据发生改变时调用。
- void endAnimation():当某个动画需要被立即停止时调用,这里一般做视图的状态恢复。
- void endAnimations() 作用和endAnimation()一样,区别是停止多个动画时调用。
具体就不说了,demo已上传github,代码戳我.