失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > RecyclerView实现滑动删除和拖拽功能

RecyclerView实现滑动删除和拖拽功能

时间:2018-08-31 21:44:43

相关推荐

RecyclerView实现滑动删除和拖拽功能

源码传送门

前言

从Android 5.0开始,谷歌推出了新的控件RecyclerView,相对于早它之前的ListView,优点多多,功能强大,也给我们的开发着提供了极大的便利,今天自己学习一下RecyclerView轻松实现滑动删除及拖拽的效果,如下图。

这里写图片描述

相信研究过RecyclerView的同学,应该很清楚该怎么实现这样的效果,若是用ListView,这样的效果实现起来可能就有点麻烦,但是在强大的RecyclerView面前这样的的效果只需很少的代码,因为谷歌给我们提供了强大的工具类ItemTouchHelper,它已经处理了关于RecyclerView拖动和滑动的实现,并且我们可以在其中实现我们自己的动画,以及定制我们想要的效果。

ItemTouchHelper.Callback

ItemTouchHelper.Callback有几个重要的抽象方法,我们继承该抽象类,并重写抽象方法。它是我们实现滑动和拖拽重要的回调。

int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder)复制代码

该方法返回一个整数,用来指定拖拽和滑动在哪个方向是被允许的。在其中使用makeMovementFlags(int dragFlags, int swipeFlags)返回,该方法第一个参数用来指定拖动,第二个参数用来指定滑动。对于方向参数有6种

ItemTouchHelper.UP //滑动拖拽向上方向ItemTouchHelper.DOWN//向下ItemTouchHelper.LEFT//向左ItemTouchHelper.RIGHT//向右ItemTouchHelper.START//依赖布局方向的水平开始方向ItemTouchHelper.END//依赖布局方向的水平结束方向复制代码

boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target)复制代码

onMove方法是拖拽的回调,参数viewHolder是拖动的Item,target是拖动的目标位置的Item,该方法如果返回true表示切换了位置,反之返回false。

void onSwiped(RecyclerView.ViewHolder viewHolder, int direction)复制代码

onSwiped方法为Item滑动回调,viewHolder为滑动的item,direction为滑动的方向。

上面三个方法是必须重写的方法,当然还有其它一些可供选择的方法。

/*** Item是否支持长按拖动** @return*true 支持长按操作*false 不支持长按操作*/boolean isLongPressDragEnabled()/*** Item是否支持滑动** @return*true 支持滑动操作*false 不支持滑动操作*/boolean isItemViewSwipeEnabled()/*** 移动过程中绘制Item** @param c* @param recyclerView* @param viewHolder* @param dX*X轴移动的距离* @param dY*Y轴移动的距离* @param actionState*当前Item的状态* @param isCurrentlyActive*如果当前被用户操作为true,反之为false*/onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive)复制代码

需要注意的是,如果我们想实现拖动或者滑动必须将上面是否支持拖动或者滑动的方法返回true,否则onMove或者onSwiped方法不会执行。

功能实现

adapter=new CustomAdapter(getActivity(),strings);recycleview.setAdapter(adapter);ItemTouchHelper.Callback callback=new RecycleItemTouchHelper(adapter);ItemTouchHelper itemTouchHelper=new ItemTouchHelper(callback);itemTouchHelper.attachToRecyclerView(recycleview);复制代码

对于ItemTouchHelper 构造方法接收一个ItemTouchHelper.Callback参数,而这个Callback就是我们在在上述讲到的工具类,初始化ItemTouchHelper 后通过其attachToRecyclerView(@Nullable RecyclerView recyclerView)方法将我们实现的ItemTouchHelper.Callback和RecyclerView关联,最终达到我们的效果,代码看起来是不是很简单,接下来我们看下我们自定义的Callback。

package com.example.xh.adapter;import android.content.res.Resources;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.Rect;import android.support.v7.widget.RecyclerView;import android.support.v7.widget.helper.ItemTouchHelper;import android.util.Log;import android.view.View;import com.example.xh.R;import com.example.xh.utils.MyApplication;/*** Created by xiehui on /2/23.*/public class RecycleItemTouchHelper extends ItemTouchHelper.Callback{private static final String TAG ="RecycleItemTouchHelper" ;private final ItemTouchHelperCallback helperCallback;public RecycleItemTouchHelper(ItemTouchHelperCallback helperCallback) {this.helperCallback = helperCallback;}/*** 设置滑动类型标记** @param recyclerView* @param viewHolder* @return*返回一个整数类型的标识,用于判断Item那种移动行为是允许的*/@Overridepublic int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {Log.e(TAG, "getMovementFlags: " );//START 右向左 END左向右 LEFT 向左 RIGHT向右 UP向上//如果某个值传0,表示不触发该操作,次数设置支持上下拖拽,支持向右滑动return makeMovementFlags(ItemTouchHelper.UP|ItemTouchHelper.DOWN,ItemTouchHelper.END );}/*** Item是否支持长按拖动** @return*true 支持长按操作*false 不支持长按操作*/@Overridepublic boolean isLongPressDragEnabled() {return super.isLongPressDragEnabled();}/*** Item是否支持滑动** @return*true 支持滑动操作*false 不支持滑动操作*/@Overridepublic boolean isItemViewSwipeEnabled() {return super.isItemViewSwipeEnabled();}/*** 拖拽切换Item的回调** @param recyclerView* @param viewHolder* @param target* @return*如果Item切换了位置,返回true;反之,返回false*/@Overridepublic boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {Log.e(TAG, "onMove: " );helperCallback.onMove(viewHolder.getAdapterPosition(),target.getAdapterPosition());return true;}/*** 滑动Item** @param viewHolder* @param direction* Item滑动的方向*/@Overridepublic void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {Log.e(TAG, "onSwiped: ");helperCallback.onItemDelete(viewHolder.getAdapterPosition());}/*** Item被选中时候回调** @param viewHolder* @param actionState*当前Item的状态*ItemTouchHelper.ACTION_STATE_IDLE 闲置状态*ItemTouchHelper.ACTION_STATE_SWIPE 滑动中状态*ItemTouchHelper#ACTION_STATE_DRAG 拖拽中状态*/@Overridepublic void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {super.onSelectedChanged(viewHolder, actionState);}public interface ItemTouchHelperCallback{void onItemDelete(int positon);void onMove(int fromPosition,int toPosition);}}复制代码

在默认情况下是支持拖动和滑动的,也就是isLongPressDragEnabled()和isItemViewSwipeEnabled()是返回true的。在该类中我们创建了一个接口ItemTouchHelperCallback并创建两个抽象方法,分别表示拖拽和滑动。在onMove方法中回调创建我们创建的接口方法接口onMove(int fromPosition,int toPosition),并将拖拽和 Item 的posion和目标posion传入,posion通过ViewHolder的getAdapterPosition()获得,然后在滑动回调方法onSwiped中回调onItemDelete(int positon)。到这里我们自定义的ItemTouchHelper.Callback创建完成。

上面完成后我们只需要在我们自定义的Adapter中实现RecycleItemTouchHelper.ItemTouchHelperCallback接口,然后在回调方法中更新界面,如下Apdater中回调方法实现。

@Overridepublic void onItemDelete(int positon) {list.remove(positon);notifyItemRemoved(positon);}@Overridepublic void onMove(int fromPosition, int toPosition) {Collections.swap(list,fromPosition,toPosition);//交换数据notifyItemMoved(fromPosition,toPosition);}复制代码

我们在onItemDelete方法中删除对应posion的数据,在onMove方法中通过Collections.swap方法交换对应项数据,然后分别调用notifyItemRemoved和notifyItemMoved通过适配器更新UI.

好了到这里功能已经实现了,是不是发现代码很少,当然啰嗦的比较多而已。

功能升级

通过上面简单代码的实现,已经可以滑动删除和拖拽了,当然不满足的你可能发现滑动删除的时候没有动画没有背景,但是我想更改下背景并且在滑动的过程会出现一个删除的图标,给用户反馈,让其明白该操作是删除数据的。当然你还会想再删除的过程中增加一个动画。其实实现这个效果也并不是很麻烦,接下来新的方法实现登场。哦,不对,前面提到过的。

onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive)复制代码

该方法就是移动过程中绘制Item的回调。我们在actionState==ItemTouchHelper.ACTION_STATE_SWIPE时,即为滑动的时候绘制背景和删除图片。

初始化

/*** 移动过程中绘制Item** @param c* @param recyclerView* @param viewHolder* @param dX*X轴移动的距离* @param dY*Y轴移动的距离* @param actionState*当前Item的状态* @param isCurrentlyActive*如果当前被用户操作为true,反之为false*/@Overridepublic void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {//滑动时自己实现背景及图片if (actionState==ItemTouchHelper.ACTION_STATE_SWIPE){//dX大于0时向右滑动,小于0向左滑动View itemView=viewHolder.itemView;//获取滑动的viewResources resources= MyApplication.getAppContext().getResources();Bitmap bitmap= BitmapFactory.decodeResource(resources, R.drawable.delete);//获取删除指示的背景图片int padding =10;//图片绘制的paddingint maxDrawWidth=2*padding+bitmap.getWidth();//最大的绘制宽度Paint paint=new Paint();paint.setColor(resources.getColor(R.color.btninvalid));int x=Math.round(Math.abs(dX));int drawWidth=Math.min(x,maxDrawWidth);//实际的绘制宽度,取实时滑动距离x和最大绘制距离maxDrawWidth最小值int itemTop=itemView.getBottom()-itemView.getHeight();//绘制的top位置//向右滑动if(dX>0){//根据滑动实时绘制一个背景c.drawRect(itemView.getLeft(),itemTop,drawWidth,itemView.getBottom(),paint);//在背景上面绘制图片if (x>padding){//滑动距离大于padding时开始绘制图片//指定图片绘制的位置Rect rect=new Rect();//画图的位置rect.left=itemView.getLeft()+padding;rect.top=itemTop+(itemView.getBottom()-itemTop-bitmap.getHeight())/2;//图片居中int maxRight=rect.left+bitmap.getWidth();rect.right=Math.min(x,maxRight);rect.bottom=rect.top+bitmap.getHeight();//指定图片的绘制区域Rect rect1=null;if (x<maxRight){rect1=new Rect();//不能再外面初始化,否则dx大于画图区域时,删除图片不显示rect1.left=0;rect1.top = 0;rect1.bottom=bitmap.getHeight();rect1.right=x-padding;}c.drawBitmap(bitmap,rect1,rect,paint);}//绘制时需调用平移动画,否则滑动看不到反馈itemView.setTranslationX(dX);}else {//如果在getMovementFlags指定了向左滑动(ItemTouchHelper。START)时则绘制工作可参考向右的滑动绘制,也可直接使用下面语句交友系统自己处理super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);}}else {//拖动时有系统自己完成super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);}}复制代码

经过上面的处理,发现此时滑动可以看到我们定制的蓝低的删除背景了,此时可能还有疑问,这样删除是不是很生硬,那就再给它加一个透明度的动画,如下。

float alpha = 1.0f - Math.abs(dX) / (float) itemView.getWidth();itemView.setAlpha(alpha);复制代码

好了,到这里RecyclerView实现滑动删除和拖拽功能的已经介绍完毕了。有问题欢迎留言指出,Have a wonderful day .

如果觉得《RecyclerView实现滑动删除和拖拽功能》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。