RecyclerView的常见用法总结
2017-09-14 11:17
267 查看
RecyclerView的简单用法我们已经再熟悉不过了,这里就不多说了,下面主要说一下RecyclerView比较好用的一些功能,先看下效果图
下面我们将对这些功能进行逐一实现
但是我们使用RecyclerView添加这些对我们是一点用都没有的。然而RecyclerView提供了更加高级的用法:
有了这个方法我们就可以定制自己的分隔线,我们只要实现RecyclerView.ItemDecoration
下的两个方法
getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state)
和
onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state)
我们的RecyclerView的ItemView周围实际上可以用下图表示
绿色的部分就是我们的itemView,橙色的部分就是我们的outRect,我们给outRect设置left,top,right,bottom实际上就是设置我们的itemView与其他控件的偏移量,我们这里想设置分隔线,只需要给我们的outRect设置outRect.top=1px,留出1px的间距供我们去绘制分隔线。
最后在onDraw方法中计算出分隔线矩形的left,top,right和bottom绘制出来就可以了
我们这里同时处理了LinearLayoutManager和GridLayoutManager的分隔线,LinearLayoutManager的分隔线比较简单,GridLayoutManger我们需要考虑到最后一列不需要绘制右侧分隔线,最后一行不需要绘制底部分隔线,我们判断是否是右侧或者左侧代码如下:
具体的计算和绘制的过程:(其实分隔线就是绘制一个矩形就)
熟悉View事件分发机制的,对这两个方法应该都不陌生,我们可以拦截我们的View事件,然后交由GestureDetectorCompat手势识别类进行处理我们的手势,然后根据单击和长按分别调用我们定义的接口回调方法:
这样我们就轻松的实现了RecyclerView的单击和长按操作
详细代码如下:
这其中
根据我们按下的坐标位置找到我们RecyclerView中的具体某一个itemView
根据我们的ItemView找到相应的ViewHolder
(1)拖拽移动需要我们实现下面两个方法
a:
getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder)
我们在长按ItemView的时候会调用这个方法,我们可以在这个方法里面定义我们LinearLayoutManager和GridLayoutManager的移动的方法
ItemTouchHelper.UP
ItemTouchHelper.DOWN
ItemTouchHelper.LEFT
ItemTouchHelper.RIGHT
滑动的方向
ItemTouchHelper.START
ItemTouchHelper.END
然后调用makeMovementFlags设置我们移动和滑动的方向
/**
* 当长按itemView移动的时候调用这个方法
* @param recyclerView
* @param viewHolder
* @return
*/
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
if (recyclerView.getLayoutManager() instanceof GridLayoutManager) { //因为GridLayout有上下左右四个方向,所以dragFlags设置为上下左右
int dragFlags = android.support.v7.widget.helper.ItemTouchHelper.UP | android.support.v7.widget.helper.ItemTouchHelper.DOWN
| android.support.v7.widget.helper.ItemTouchHelper.LEFT | android.support.v7.widget.helper.ItemTouchHelper.RIGHT;
int swipeFlags = 0; //设置为零表示不能够侧滑删除
return makeMovementFlags(dragFlags, swipeFlags);
} else {
int dragFlags = android.support.v7.widget.helper.ItemTouchHelper.UP | android.support.v7.widget.helper.ItemTouchHelper.DOWN; //线性布局只要上下两个方向
int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
return makeMovementFlags(dragFlags, swipeFlags);
}
}
b:
当我们长按移动ItemView的时候会不断的走这个方法,在这里我们可以根据长按移动交换itemView的位置,具体实现如下:
/**
* 长按移动itemView的时候调用这个方法
* @param recyclerView
* @param viewHolder
* @param target
* @return
*/
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
int fromPosition = viewHolder.getAdapterPosition(); //按下的位置
int targetPosition = target.getAdapterPosition(); //移动到的位置
if(recyclerView.getLayoutManager() instanceof GridLayoutManager){ //如果是GridLayoutManager,在第0位不能拖动和被覆盖掉
if (targetPosition == 0) {
return false;
}
}
if (fromPosition < targetPosition) {
for (int i = fromPosition; i < targetPosition; i++) {
Collections.swap(mAdapter.getDataList(), i, i + 1);
}
} else {
for (int i = fromPosition; i > targetPosition; i--) {
Collections.swap(mAdapter.getDataList(), i, i - 1);
}
}
mAdapter.notifyItemMoved(fromPosition, targetPosition);
return true;
}
(2)侧滑删除需要我们实现下面这个方法
onSwiped(RecyclerView.ViewHolder viewHolder, int direction)
具体实现
源代码
参考链接:
http://www.10tiao.com/html/227/201705/2650239745/1.html https://mp.weixin.qq.com/s/LsxYOGnp6Yq_9rFHUDAL9A
下面我们将对这些功能进行逐一实现
一、添加分隔线
我们知道ListView添加分隔线是一件很简单的事情,我们添加以下代码就可以:android:divider="@color/colorAccent" android:dividerHeight="2dp"
但是我们使用RecyclerView添加这些对我们是一点用都没有的。然而RecyclerView提供了更加高级的用法:
addItemDecoration()
有了这个方法我们就可以定制自己的分隔线,我们只要实现RecyclerView.ItemDecoration
下的两个方法
getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state)
和
onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state)
我们的RecyclerView的ItemView周围实际上可以用下图表示
绿色的部分就是我们的itemView,橙色的部分就是我们的outRect,我们给outRect设置left,top,right,bottom实际上就是设置我们的itemView与其他控件的偏移量,我们这里想设置分隔线,只需要给我们的outRect设置outRect.top=1px,留出1px的间距供我们去绘制分隔线。
最后在onDraw方法中计算出分隔线矩形的left,top,right和bottom绘制出来就可以了
我们这里同时处理了LinearLayoutManager和GridLayoutManager的分隔线,LinearLayoutManager的分隔线比较简单,GridLayoutManger我们需要考虑到最后一列不需要绘制右侧分隔线,最后一行不需要绘制底部分隔线,我们判断是否是右侧或者左侧代码如下:
/** * 是否是最后一行 * @param parent * @param position * @return */ public boolean isLastRow(RecyclerView parent,int position){ int itemCount = parent.getAdapter().getItemCount(); //itemView的总数 GridLayoutManager gridLayoutManager = (GridLayoutManager) parent.getLayoutManager(); int spanCount = gridLayoutManager.getSpanCount(); //gridLayoutManager有多少列 itemCount = itemCount - itemCount % spanCount; if(position>=itemCount) return true; else return false; } /** * 是否是最后一列 * @param parent * @param position * @return */ public boolean isLastColunm(RecyclerView parent,int position){ GridLayoutManager gridLayoutManager = (GridLayoutManager) parent.getLayoutManager(); int spanCount = gridLayoutManager.getSpanCount(); if((position+1) % spanCount == 0) return true; else return false; }
具体的计算和绘制的过程:(其实分隔线就是绘制一个矩形就)
@Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { super.getItemOffsets(outRect, view, parent, state); int position = parent.getChildAdapterPosition(view); //根据itemView获取在RecyclerView中的位置 RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); if (layoutManager instanceof GridLayoutManager) { //网格布局 if (isLastColunm(parent,position)) { outRect.bottom = (int) dividerHeight; //是最后一列的话,只绘制底部的分隔线 } else if(isLastRow(parent,position)){ outRect.right = (int) dividerHeight; //是最后一行的话,只绘制右侧的分隔线 }else{ outRect.bottom = (int) dividerHeight; outRect.right = (int) dividerHeight; } } else { //线性布局 if (position != 0) { outRect.top = (int) dividerHeight; } } } @Override public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) { super.onDraw(canvas, parent, state); int childCount = parent.getChildCount(); if (parent.getLayoutManager() instanceof GridLayoutManager) { for (int i = 0; i < childCount; i++) { View childView = parent.getChildAt(i); int left = childView.getLeft(); int top = childView.getTop(); int right = childView.getRight(); int bottom = childView.getBottom(); int childAdapterPosition = parent.getChildAdapterPosition(childView); if (isLastColunm(parent,childAdapterPosition)) { //最后一列的分隔线 canvas.drawRect(left, bottom, right, bottom+dividerHeight, mPaint); } else if(isLastRow(parent,childAdapterPosition)){ //最后一行的分隔线 canvas.drawRect(right, top, right+dividerHeight, bottom, mPaint); }else{ canvas.drawRect(left, bottom, right+dividerHeight, bottom+dividerHeight, mPaint); canvas.drawRect(right, top, right+dividerHeight, bottom, mPaint); } } } else { //绘制线性布局的itemView之间的分隔线 for (int i = 0; i < childCount; i++) { View itemView = parent.getChildAt(i); int childAdapterPosition = parent.getChildAdapterPosition(itemView); if (childAdapterPosition == 0) { //如果是第一条,不绘制分割线 continue; } int dividerLeft = parent.getPaddingLeft(); int dividerTop = (int) (itemView.getTop() - dividerHeight); int dividerRight = parent.getWidth() - parent.getPaddingRight(); int dividerBottom = itemView.getTop(); canvas.drawRect(dividerLeft, dividerTop, dividerRight, dividerBottom, mPaint); } } }
二、添加点击和长按
RecyclerView没有提供类似setOnItemCickListener这样的接口来供我们实现单击itemView的操作。RecyclerView提供了addOnItemTouchListener,我们可以实现RecyclerView.OnItemTouchListener这个接口中的两个方法onInterceptTouchEvent(RecyclerView rv, MotionEvent e) onTouchEvent(RecyclerView rv, MotionEvent e)
熟悉View事件分发机制的,对这两个方法应该都不陌生,我们可以拦截我们的View事件,然后交由GestureDetectorCompat手势识别类进行处理我们的手势,然后根据单击和长按分别调用我们定义的接口回调方法:
//RecyclerView条目的单击 public abstract void onItemClick(RecyclerView.ViewHolder holder); //RecyclerView的长按 public abstract void onItemLongPress(RecyclerView.ViewHolder holder);
这样我们就轻松的实现了RecyclerView的单击和长按操作
详细代码如下:
@Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { mGestureDetectorCompat.onTouchEvent(e); return false; } @Override public void onTouchEvent(RecyclerView rv, MotionEvent e) { mGestureDetectorCompat.onTouchEvent(e); } @Override public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { } public class OnItemGestureListener extends GestureDetector.SimpleOnGestureListener { @Override public boolean onSingleTapUp(MotionEvent e) { //findChildViewUnder根据点击的x,y坐标找到点击的位置所属的view View childViewUnder = mRecyclerView.findChildViewUnder(e.getX(), e.getY()); if(childViewUnder!=null){ //找到RecyclerView点击x,y位置的View的ViewHolder RecyclerView.ViewHolder viewHolder = mRecyclerView.getChildViewHolder(childViewUnder); onItemClick(viewHolder); } return true; } @Override public void onLongPress(MotionEvent e) { View childViewUnder = mRecyclerView.findChildViewUnder(e.getX(), e.getY()); if(childViewUnder!=null){ RecyclerView.ViewHolder childViewHolder = mRecyclerView.getChildViewHolder(childViewUnder); onItemLongPress(childViewHolder); } } }
这其中
findChildViewUnder
根据我们按下的坐标位置找到我们RecyclerView中的具体某一个itemView
getChildViewHolder
根据我们的ItemView找到相应的ViewHolder
三、拖拽移动、侧滑删除(我们这里同时实现了线性和网格布局的拖动,线性的侧滑删除)
RecyclerView实现侧滑删除是一件非常容易的事情,ItemTouchHelper就是用来辅助RecyclerView来实现各种删除侧滑操作的。我们的只要继承ItemTouchHelper.Callback并实现其中的个方法:(1)拖拽移动需要我们实现下面两个方法
a:
getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder)
我们在长按ItemView的时候会调用这个方法,我们可以在这个方法里面定义我们LinearLayoutManager和GridLayoutManager的移动的方法
ItemTouchHelper.UP
ItemTouchHelper.DOWN
ItemTouchHelper.LEFT
ItemTouchHelper.RIGHT
滑动的方向
ItemTouchHelper.START
ItemTouchHelper.END
然后调用makeMovementFlags设置我们移动和滑动的方向
/**
* 当长按itemView移动的时候调用这个方法
* @param recyclerView
* @param viewHolder
* @return
*/
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
if (recyclerView.getLayoutManager() instanceof GridLayoutManager) { //因为GridLayout有上下左右四个方向,所以dragFlags设置为上下左右
int dragFlags = android.support.v7.widget.helper.ItemTouchHelper.UP | android.support.v7.widget.helper.ItemTouchHelper.DOWN
| android.support.v7.widget.helper.ItemTouchHelper.LEFT | android.support.v7.widget.helper.ItemTouchHelper.RIGHT;
int swipeFlags = 0; //设置为零表示不能够侧滑删除
return makeMovementFlags(dragFlags, swipeFlags);
} else {
int dragFlags = android.support.v7.widget.helper.ItemTouchHelper.UP | android.support.v7.widget.helper.ItemTouchHelper.DOWN; //线性布局只要上下两个方向
int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
return makeMovementFlags(dragFlags, swipeFlags);
}
}
b:
onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target)
当我们长按移动ItemView的时候会不断的走这个方法,在这里我们可以根据长按移动交换itemView的位置,具体实现如下:
/**
* 长按移动itemView的时候调用这个方法
* @param recyclerView
* @param viewHolder
* @param target
* @return
*/
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
int fromPosition = viewHolder.getAdapterPosition(); //按下的位置
int targetPosition = target.getAdapterPosition(); //移动到的位置
if(recyclerView.getLayoutManager() instanceof GridLayoutManager){ //如果是GridLayoutManager,在第0位不能拖动和被覆盖掉
if (targetPosition == 0) {
return false;
}
}
if (fromPosition < targetPosition) {
for (int i = fromPosition; i < targetPosition; i++) {
Collections.swap(mAdapter.getDataList(), i, i + 1);
}
} else {
for (int i = fromPosition; i > targetPosition; i--) {
Collections.swap(mAdapter.getDataList(), i, i - 1);
}
}
mAdapter.notifyItemMoved(fromPosition, targetPosition);
return true;
}
(2)侧滑删除需要我们实现下面这个方法
onSwiped(RecyclerView.ViewHolder viewHolder, int direction)
具体实现
/** * 侧滑删除的时候调用这个方法 * @param viewHolder * @param direction */ @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { int adapterPosition = viewHolder.getAdapterPosition(); mAdapter.notifyItemRemoved(adapterPosition); mAdapter.getDataList().remove(adapterPosition); }
源代码
参考链接:
http://www.10tiao.com/html/227/201705/2650239745/1.html https://mp.weixin.qq.com/s/LsxYOGnp6Yq_9rFHUDAL9A
相关文章推荐
- RecyclerView 使用方法总结(一):RecyclerView的基本用法,及实现ListView
- RecyclerView用法总结
- Android开发:SurfaceView基本用法总结
- (一)RecyclerView简单使用总结
- Android5.x 新控件之RecyclerView使用总结
- Android列表RecyclerView的用法
- webView的用法总结。
- RecyclerView的用法
- Android Intent 常见用法总结
- [转]EasyUI——常见用法总结
- RecyclerView的用法
- Android控件RecyclerView的基本用法
- Android动画学习Demo(1) 关于ViewAnimation的用法及总结
- 常见的typedef用法总结
- 关于Recyclerview的一些常见问题
- 关于WebView的总结2---使用方法及常见问题和解决方案汇总
- Android UI 之 RecyclerView实现常见首页布局
- Android WebView常见问题总结
- RecyclerView封装详解完美用法一
- Android的ListView和RecyclerView的基本用法