实现拖拽效果二: 使用RecyclerView + ItemTouchHelper 实现拖拽、删除,滑动删除效果
因为demo适配了公司的业务,具体图层不好放出来,难受。但是这毕竟只是记录学习,自己知道实现了就好!
之前是使用GridView实现的拖拽效果,但是其实他存在一个问题,当时涉及我本身的业务,所以使用那个很难实现,所以发现了这个。
GridView如果要实现横向滚动实现分页功能,并且支持拖拽互换就存在很大的问题,当然不同的trager也是可以实现的,但是很不方便,然后使用ItemTouchHelper实现就会很方便。横向滚动实现分页使用RecyclerView+ItemTouchHelper本身相较于GridView实现就简单很多,并且是google官方支持,丝毫不慌。
那么再整理思路,要完成那些方面,需要注意以下几点:
- 要解耦!不要一大堆文件全部卸载一两个java文件中,看着脑壳痛,让后期接手的人拿头维护。
- 业务需求的实现:分页和间隔。间隔必不可少,其次使用过recyclerView的都知道recyclerView是可以随意滚动的,要实现分页,像GridView+ViewPage实现效果,那就不能使得它能够随意滚动,而是一次滚动响应的列数(因为我这里是水平滚动,竖向类同)。
- 交互效果,也需要震动啊,改变底色啊等等
- 持久化,点击仿重等
这个实现方法比GridView实现着实简单很多,主要是代码的解耦啊,了解以下recyclerView和ItemTouchHelper的了解啊和具体的业务需求。
解耦
首先实现解耦,我的文件目录如下:
从上往下分别是
- 实现分页效果的helper
- 适配器
- 回调 这个就是集成itemTouchHelper.Callback,用来实现拖拽效果。
- itemTouchHelper和适配器之间的接口,实现解耦,具体的工作全部交给适配器去做
- 间隔
itemTouchHelper实现
itemTouchHelper是google为我们封装的为recyclerView实现的可以拖拽交换item,侧滑删除item的封装类。
我们这里要完成这个效果,主要是集成itemTouchHelper.Callback接口就行。
必须完成的有三个函数:
- getMovementFlags :设置拖拽方向和滑动方向。
- onMove:实现拖拽移动的时候的监听。
- onSwiped:实现滑动删除
其次之外涉及以下几个我们需要实现的父类的函数:
- isLongPressDragEnabled(): 是否支持长按删除 (其实不弄也许)
- isItemViewSwipeEnable():是否支持滑动删除(其实不弄也行,但是放在自己眼皮子底下放心点)
- onSelectdChanged():选中的时候,会调用这个方法,在这里实现长按选中的震动、改变底色效果等
- clearView():事件结束了,Up手指了,这里也是调用实现onSelectedChanged设置底色改变的取消等操作
- onChildDraw():这里实现自己的自定义的交互规则,或者动画效果这里也行,我这里完成了拖拽删除的自定义交互效果。
完整的源码如下,具体的注释都有:
public class MyItemTouchHelperCallback extends ItemTouchHelper.Callback {
private MyItemTouchHelperListener mListener; //适配器和itemTouchHelper之间的接口,完成解耦
private boolean up;
public MyItemTouchHelperCallback(MyItemTouchHelperListener mListener){
this.mListener = mListener;
}
/**
* 设置拖拽方向、滑动方向
* @param recyclerView
* @param viewHolder
* @return
*/
@Override
public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
int dragFlags = 0;
int swipeFlags = ItemTouchHelper.UP;
if (recyclerView.getLayoutManager() instanceof GridLayoutManager || recyclerView.getLayoutManager() instanceof StaggeredGridLayoutManager){
dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.RIGHT | ItemTouchHelper.LEFT;
}
else {
dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
}
return makeMovementFlags(dragFlags,swipeFlags);
}
/**
* 拖拽移动
* @param recyclerView
* @param viewHolder
* @param target
* @return
*/
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
int fromPosition = viewHolder.getAdapterPosition();
int toPosition = target.getAdapterPosition();
mListener.onItemMove(fromPosition,toPosition);
return true;
}
/**
* 滑动删除
* @param viewHolder
* @param direction
*/
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
// mListener.onItemDelete(viewHolder.getAdapterPosition());
}
/**
* 是否支持长按拖拽
* @return
*/
@Override
public boolean isLongPressDragEnabled(){
return true;
}
/**
* 是否支持滑动
* @return
*/
@Override
public boolean isItemViewSwipeEnabled(){
return false;
}
/**
* 选中的时候,会调用这个方法
* @param viewHolder
* @param actionState
*/
@Override
public void onSelectedChanged(@Nullable RecyclerView.ViewHolder viewHolder, int actionState) {
//不等于休闲的时候,也就是被选中了
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE){
up = false;
mListener.onSelectedItem(viewHolder);
}
super.onSelectedChanged(viewHolder, actionState);
}
/**
* 事件结束
* @param recyclerView
* @param viewHolder
*/
@Override
public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
mListener.onSelectedFinish(viewHolder);
super.clearView(recyclerView, viewHolder);
}
/**
* 完成自定义的交互规则
* 完成对item拖拽到一定位置的删除
*
*/
@Override
public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
if (mListener == null)
return;
// Log.d(TAG, "onChildDraw:dY " + dY);
//因为dY是以本身为坐标的,所以只要他向上就为负的,向下就为正的,所以要
//记录相关变化,使得控件完全画出界面就删除
int result = viewHolder.itemView.getBottom();
float res = result+dY;
int index = viewHolder.getAdapterPosition();
// Log.d(TAG, "onChildDraw:Result " + res);
// Log.d(TAG, "onChildDraw:Position " + viewHolder.getAdapterPosition());
if (res < 0){
if (up){ //这里的up必须有,否则删除了当前item一会,因为还在滑动,会返回index为-1
mListener.onItemDelete(index);
up = false;
}
// Log.d(TAG, "onChildDraw: "+index);
}
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, is