前言从Android5.0开始,谷歌推出了一个新的控件RecyclerView。与之前的ListView相比,它有很多优点和强大的功能,也为我们的开发者带来了很大的好处。方便,今天自学RecyclerView,轻松实现滑动删除拖拽的效果,如下图。相信学过RecyclerView的同学应该很清楚如何实现这样的效果。如果使用ListView,这样的效果实现起来可能会有点麻烦,但是在强大的RecyclerView面前,这样的效果只需要很少的代码,因为谷歌给我们提供了一个强大的工具类ItemTouchHelper,它已经处理了实现在RecyclerView上拖拽滑动,我们可以在里面实现自己的动画,也可以自定义自己想要的效果。ItemTouchHelper.Callback有几个重要的抽象方法,我们继承这个抽象类并重写抽象方法。是我们实现滑动拖动的重要回调。intgetMovementFlags(RecyclerViewrecyclerView,RecyclerView.ViewHolderviewHolder)该方法返回一个整数,指定允许在哪个方向拖拽和滑动。使用makeMovementFlags(intdragFlags,intswipeFlags)返回,该方法第一个参数用于指定拖动,第二个参数用于指定滑动。方向参数有6种ItemTouchHelper.UP//向上滑动拖动方向ItemTouchHelper.DOWN//向下ItemTouchHelper.LEFT//向左ItemTouchHelper.RIGHT//向右ItemTouchHelper.START//水平启动方向ItemTouchHelper取决于布局方向.END//根据布局方向的横向结束方向booleanonMove(RecyclerViewrecyclerView,RecyclerView.ViewHolderviewHolder,RecyclerView.ViewHoldertarget)onMove方法是拖拽的回调,参数viewHolder是要拖拽的item,target是要拖拽的item被拖。如果该方法返回true,则表示位置已经切换,否则返回false。voidonSwiped(RecyclerView.ViewHolderviewHolder,intdirection)onSwiped方法为Item滑动回调,viewHolder为滑动item,direction为滑动方向。以上三种方法都是必须重写的方法,当然还有其他替代方法。/***Item支持长按拖动**@return*true支持长按操作*false不支持长按操作*/ooleanisLongPressDragEnabled()/***Item支持滑动**@return*true支持滑动操作*false不支持滑动操作*/ooleanisItemViewSwipeEnabled()/***移动时绘制Item**@paramc*@paramrecyclerView*@paramviewHolder*@paramdX*X轴移动距离*@paramdY*Y轴移动距离*@paramactionState*当前Item的状态*@paramisCurrentlyActive*如果当前被用户操作则为true,否则为false*/nChildDraw(Canvasc,RecyclerViewrecyclerView,RecyclerView.ViewHolderviewHolder,floatdX,floatdY,intactionState,booleanisCurrentlyActive)应该是注意,如果我们要实现Draggingorsliding必须返回true上面的方法是否支持拖动或滑动,否则onMove或onSwiped方法将不会被执行。功能实现adapter=newCustomAdapter(getActivity(),strings);recycleview.setAdapter(adapter);ItemTouchHelper.Callbackcallback=newRecycleItemTouchHelper(adapter);ItemTouchHelperitemTouchHelper=newItemTouchHelper(callback);itemTouchHelper.attachToRecyclerView(recycleview);对于ItemTouchHelper构造方法接收一个ItemTouchHelper.Callback参数,而这个Callback就是我们上面提到的工具类。初始化ItemTouchHelper后,我们通过它的attachToRecyclerView(@NullableRecyclerViewrecyclerView)方法将我们实现的ItemTouchHelper.Callback和RecyclerView关联起来,最终实现我们的效果。看代码是不是很简单,来看看我们自定义的Callback。packagecom.example.xh.adapter;importandroid.content.res.Resources;importandroid.graphics.Bitmap;importandroid.graphics.BitmapFactory;importandroid.graphics.Canvas;importandroid.graphics.Paint;importandroid.graphics.Rect;importandroid.support。v7.widget.RecyclerView;importandroid.support.v7.widget.helper.ItemTouchHelper;importandroid.util.Log;importandroid.view.View;importcom.example.xh.R;importcom.example.xh.utils.MyApplication;/***Createdbyxiehuion2017/2/23.*/publicclassRecycleItemTouchHelperextendsItemTouchHelper.Callback{privatestaticfinalStringTAG="RecycleItemTouchHelper";privatefinalItemTouchHelperCallbackhelperCallback;publicRecycleItemTouchHelper(ItemTouchHelperCallbackhelperCallback){this.helperCallback=helperCallback;}/***设置滑动类型标记**@paramrecyclerView*@paramviewHolder*@return*返回一个整数类型的标识,用于判断Item的移动行为是否被允许*/@OverridepublicintgetMovementFlags(RecyclerViewrecyclerView,RecyclerView.ViewHolderviewHolder){Log.e(TAG,"getMovementFlags:");//STARTrighttoleftENDlefttorightLEFTtoleftRIGHTtorightUPup//如果传值为0,表示不触发操作,次数设置支持上下拖动和向右滑动(ItemTouchHelper.UP|ItemTouchHelper.DOWN,ItemTouchHelper.END);}/***Item支持长按拖动**@return*true支持长按操作*false不支持长按操作*/@OverridepublicbooleanisLongPressDragEnabled(){returnsuper.isLongPressDragEnabled();}/***Item支持滑动**@return*true支持滑动操作*false不支持滑动操作*/@OverridepublicbooleanisItemViewSwipeEnabled(){returnsuper.isItemViewSwipeEnabled();}/***拖动切换Item的回调**@paramrecyclerView*@paramviewHolder*@paramtarget*@return*如果Item已经切换位置,返回true;否则返回false*/@OverridepublicbooleanonMove(RecyclerViewrecyclerView,RecyclerView.ViewHolderviewHolder,RecyclerView.ViewHoldertarget){Log.e(TAG,"onMove:");helperCallback.onMove(viewHolder.getAdapterPosition(),target.getAdapterPosition());returntrue;}/***滑动项**@paramviewHolder*@paramdirection*Item滑动方向*/@在Swiped(RecyclerView.ViewHolderviewHolder,intdirection){Log.e(TAG,"onSwiped:");helperCallback.onItemDelete(viewHolder.getAdapterPosition());}/***Item被选中时回调**@paramviewHolder*@paramactionState*当前Item状态*ItemTouchHelper.ACTION_STATE_IDLE空闲状态*ItemTouchHelper.ACTION_STATE_SWIPE滑动状态*ItemTouchHelper#ACTION_STATE_DRAG拖拽状态*/@OverridepublicvoidonSelectedChanged(RecyclerView.ViewHolderviewHolder,intactionState){super.onSelectedChanged(viewHolder,actionState);}publicinterfaceItemTouchHelperCallback{voidonItemDelete(intposition);voidonMove(intfromPosition,inttoPosition);}}默认支持拖动和滑动,即isLongPressDragEnabled()和isItemViewSwipeEnabled()返回true。在这个类中,我们创建了一个接口ItemTouchHelperCallback,并创建了两个抽象方法分别代表拖拽和滑动。在onMove方法中回调创建我们创建的接口方法interfaceonMove(intfromPosition,inttoPosition),传入拖拽和item的位置和目标位置。通过ViewHolder的getAdapterPosition()获取位置,然后在滑动回调方法onSwiped中回调onItemDelete(intposition)。至此,我们的自定义ItemTouchHelper.Callback已经创建。以上完成后,我们只需要在自定义的Adapter中实现RecycleItemTouchHelper.ItemTouchHelperCallback接口,然后在回调方法中更新接口即可,如下Adapter中回调方法的实现。@OverridepublicvoidonItemDelete(intposition){list.remove(position);notifyItemRemoved(position);}@OverridepublicvoidonMove(intfromPosition,inttoPosition){Collections.swap(list,fromPosition,toPosition);//交换数据notifyItemMoved(fromPosition,toPosition);我们在onItemDelete方法中删除posion对应的数据,在onMove方法中通过Collections.swap方法交换对应的item数据,然后通过adapter调用notifyItemRemoved和notifyItemMoved来更新UI。好了,到这里功能已经实现了。有没有发现代码很Less,当然比较啰嗦。功能升级是通过上面简单的代码实现的,已经可以滑动删除和拖动了。当然,如果你不满意,你可能会发现滑动删除的时候没有动画,也没有背景,但是我想换个背景,滑动的过程中会出现一个删除。图标反馈给用户,让他们明白操作是删除数据。当然,您还希望在删除过程中添加动画。其实实现这个效果也不是很麻烦。接下来介绍一个新的方法。哦不,前面提到过。onChildDraw(Canvasc,RecyclerViewrecyclerView,RecyclerView.ViewHolderviewHolder,fl这个方法是移动时绘制Item的回调。当actionState==ItemTouchHelper.ACTION_STATE_SWIPE时,我们绘制背景,滑动时删除图片。初始化/***移动中绘制Item**@paramc*@paramrecyclerView*@paramviewHolder*@paramdX*X轴移动距离*@paramdY*Y轴移动距离*@paramactionState*当前Item状态*@paramisCurrentlyActive*如果是当前被用户操作为true,否则为false*/@OverridepublicvoidonChildDraw(Canvasc,RecyclerViewrecyclerView,RecyclerView.ViewHolderviewHolder,floatdX,floatdY,intactionState,booleanisCurrentlyActive){//滑动时自己实现背景和图片if(actionState==ItemTouchHelper.ACTION_STATE_SWIPE){//dX大于0时向右滑动,小于0时向左滑动ViewitemView=viewHolder.itemView;//获取滑动的viewResourcesresources=MyApplication.getAppContext().getResources();Bitmapbitmap=BitmapFactory.decodeResource(resources,R.drawable.delete);//获取删除指令的背景图片intpadding=10;//绘制图片的paddingintmaxDrawWidth=2*padding+bitmap.getWidth();//***Paintpaint=newPaint();paint.paint的绘画宽度。setColor(resources.getColor(R.color.btninvalid));intx=Math.round(Math.abs(dX));intdrawWidth=Math.min(x,maxDrawWidth);//实际绘制宽度,取real-时间滑动距离x和***绘图距离maxDrawWidth最小initemTop=itemView.getBottom()-itemView.getHeight();//绘图顶部位置//向右滑动if(dX>0){//root根据滑动实时绘制背景c.drawRect(itemView.getLeft(),itemTop,drawWidth,itemView.getBottom(),paint);//在背景上绘制图片if(x>padding){//当滑动距离大于padding开始绘制图片//指定绘制图片的位置rectrect=newRect();//绘制的位置rect.left=itemView.getLeft()+padding;rect.top=itemTop+(itemView.getBottom()-itemTop-bitmap.getHeight())/2;//图片居中intmaxRight=rect.left+bitmap.getWidth();rect.right=Math.min(x,maxRight);rect.bottom=rect.top+bitmap.getHeight();//指定图片的绘图区域Rectrect1=null;if(x经过上面的处理,发现这时候滑动可以看到我们自定义的蓝色和低删减背景,这时候可能会有疑问,这个删减是不是很生硬?加个透明动画就可以了,如下:floatalpha=1.0f-Math.abs(dX)/(float)itemView.getWidth();itemView.setAlpha(alpha);好了,到这里RecyclerView实现滑动删除和拖动拉取功能已经介绍过了,如果你有有什么问题欢迎留言指出,Haveawonderfulday源码传送门https://github.com/xiehui999/fuseProgram
