Android进阶七:RecyclerView拖动滑动之ItemTouchHelper
ItemTouchHelper
ItemTouchHelper是一个强大的工具,它处理好了关于在RecyclerView上添加拖动排序与滑动删除的所有事情。
它是RecyclerView.ItemDecoration的子类,也就是说它可以轻易的添加到几乎所有的LayoutManager和Adapter中。
它还可以和现有的item动画一起工作,提供受类型限制的拖放动画等等,
类介绍
主要涉及到ItemTouchHelper 和 ItemTouchHelper.Callback两个类
ItemTouchHelper主要对RecyclerView内的item的touch事件进行扩展。
ItemTouchHelper.Callback是一个抽象类,里面有一些抽象方法需要开发者去定制,包括在设置item在什么方向可以drag(拖动)和swipe(滑动),drag需要做什么,swipe需要做什么等,重写的方法如下:
1. getMovementFlags(RecyclerView, ViewHolder) 2. onMove(RecyclerView, ViewHolder, ViewHolder)3. onSwiped(ViewHolder, int)4. onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState)5. clearView(RecyclerView recyclerView,RecyclerView.ViewHolder viewHolder)6. isLongPressDragEnabled()7. isItemViewSwipeEnabled()
getMovementFlags()
这个方法是设置那些方向可以拖动和滑动RecyclerView中的item:
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;return makeMovementFlags(dragFlags, swipeFlags);
}
dragFlags表示拖动flag,swipeFlags表示滑动flag。
onMove()
拖动item的回调方法,在这里面实现拖动需要做的事情,比如RecyclerView里面item的顺序交换,
传入的参数是被拖动item的ViewHolder和目标ViewHolder
onSwiped()
滑动item的回调方法,在这里面实现滑动需要做的事情,比如RecyclerView里面item的顺序交换
onSelectedChanged()
在每次item的状态变成拖拽 (ACTION_STATE_DRAG) 或者 滑动 (ACTION_STATE_SWIPE)的时候被调用。这是把你的item view变成激活状态的最佳地点。
clearView()
item被放开或者动画完成的回调
isLongPressDragEnabled()
设置是否长按才进入拖动
isItemViewSwipeEnabled()
设置是否支持滑动操作
基本使用
代码见GitHub:iPaulPro
步骤:
扩展ItemTouchHelper.Callback类,重写getMovementFlags(),onMove(),onSwiped()等方法,类名SimpleItemTouchHelperCallback
建立RecyclerView配套的Adapter类的回调接口,Adapter类实现该接口,用于进行item删除和交换,类名ItemTouchHelperAdapter
建立ViewHolder的回调接口,ViewHolder类实现该接口,用于改变item选中和放开时候的背景改变,类名ItemTouchHelperViewHolder
实例化ItemTouchHelper,绑定RecyclerView
1.建立SimpleItemTouchHelperCallback类
SimpleItemTouchHelperCallback继承ItemTouchHelper.Callback抽象类,重写getMovementFlags(),onMove(),onSwiped()等方法
public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {private final ItemTouchHelperAdapter mAdapter;public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {mAdapter = adapter;}@Overridepublic int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;return makeMovementFlags(dragFlags, swipeFlags);}@Overridepublic boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {if (viewHolder.getItemViewType() != target.getItemViewType()) {return false;}mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());return true;}@Overridepublic void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {mAdapter.onItemDismiss(viewHolder.getAdapterPosition());}@Overridepublic boolean isLongPressDragEnabled() {return true;}@Overridepublic boolean isItemViewSwipeEnabled() {return true;}@Overridepublic void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;//回调改变item的背景颜色itemViewHolder.onItemSelected();}super.onSelectedChanged(viewHolder, actionState);}@Overridepublic void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {super.clearView(recyclerView, viewHolder);ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;//回调改变item的背景颜色itemViewHolder.onItemClear();}
}
2.建立ItemTouchHelperAdapter接口,Adapter类实现该接口
public interface ItemTouchHelperAdapter {//拖动item的回调void onItemMove(int fromPosition, int toPosition);//滑动item后删除的回调void onItemDismiss(int position);
}
public class RecyclerListAdapter extends RecyclerView.Adapter<RecyclerListAdapter.ItemViewHolder> implements ItemTouchHelperAdapter {{……//交换item@Overridepublic void onItemMove(int fromPosition, int toPosition) {String prev = mItems.remove(fromPosition);mItems.add(toPosition > fromPosition ? toPosition - 1 : toPosition, prev);notifyItemMoved(fromPosition, toPosition);}//删除item@Overridepublic void onItemDismiss(int position) {mItems.remove(position);notifyItemRemoved(position);}……
}
回调方法的调用在步骤1的onMove()和onSwiped()方法中。
notifyItemRemoved()和 notifyItemMoved()的调用非常重要,有了它们Adapter才能知道发生了改变。
3.建立ItemTouchHelperViewHolder接口,ViewHolder类实现该接口
public interface ItemTouchHelperViewHolder {//item选中的时候的回调void onItemSelected();//item放开的时候的回调void onItemClear();
}
public class ItemViewHolder extends RecyclerView.ViewHolder implements ItemTouchHelperViewHolder
{……//选中item,改变背景颜色@Overridepublic void onItemSelected() {itemView.setBackgroundColor(Color.LTGRAY);}//放开item,改变背景颜色@Overridepublic void onItemClear() {itemView.setBackgroundColor(0);}
}
回调方法的调用在步骤1的onSelectedChanged()和clearView()方法中。
4.实例化ItemTouchHelper,绑定RecyclerView
mRecyclerListAdapter = new RecyclerListAdapter(this);
mRecyclerView = (RecyclerView)findViewById(R.id.id_recycler);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setAdapter(mRecyclerListAdapter);ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(mRecyclerListAdapter);
mItemTouchHelper = new ItemTouchHelper(callback);
mItemTouchHelper.attachToRecyclerView(mRecyclerView);
以上就可以实现item的拖动和滑动操作。
滑块
当设计一个支持拖拽与拖放的列表的时候,通常都会包含一个提示可以触摸拖动的东西。它对于用户发现此功能与软件的易用性都是有帮助的,
并且Material指南也推荐 在列表处于“编辑模式”的时候这样做。让我们的例子包含一个这样的滑块也相当简单。
1.layout添加滑块
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical" android:layout_width="match_parent"android:layout_height="30dp"android:clickable="true"android:focusable="true"><TextView
android:id="@+id/id_text"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_vertical"android:textColor="#000000"android:layout_marginLeft="16dp"android:textAppearance="?android:attr/textAppearanceMedium"/><ImageView
android:id="@+id/id_img"android:layout_width="wrap_content"android:layout_height="match_parent"android:layout_gravity="center_vertical|right"android:scaleType="center"android:src="@mipmap/ic_launcher"/>
</FrameLayout>
id_img是在item中添加的一个图标,就是该滑块,当点击到这个滑块的时候,才能进行拖动操作。
2.定义接口,用于控制ItemTouchHelper直接开始执行拖动操作
public interface OnStartDragListener {void onStartDrag(RecyclerView.ViewHolder viewHolder);
}
3.RecyclerListAdapter添加id_img的触摸事件
public class RecyclerListAdapter extends RecyclerView.Adapter<RecyclerListAdapter.ItemViewHolder> implements ItemTouchHelperAdapter {private final OnStartDragListener mOnStartDragListener;@Overridepublic void onBindViewHolder(final RecyclerListAdapter.ItemViewHolder holder, int position) {holder.textView.setText(mItems.get(position));holder.handleView.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View view, MotionEvent motionEvent) {if(MotionEventCompat.getActionMasked(motionEvent) == MotionEvent.ACTION_DOWN){mOnStartDragListener.onStartDrag(holder);}return false;}});}
}
4.Activity或Fragment实现OnStartDragListener接口,调用ItemTouchHelper的startDrag立即进行拖动
public class RecyclerListFragment extends Fragment implements RecyclerListAdapter.OnDragStartListener
{……@Overridepublic void onStartDrag(RecyclerView.ViewHolder viewHolder) {mItemTouchHelper.startDrag(viewHolder);}……
}
效果:
Grid 布局
如果你想用GridLayoutManager来修改这个项目,你会发现不能正常工作。原因和解决办法都很简单:我们必须告诉ItemTouchHelper我们想支持向左拖动和向右拖动。在InSimpleItemTouchHelperCallback中,我们已经指明了:
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;return makeMovementFlags(dragFlags, swipeFlags);
}
要支持grid布局,唯一需要的修改是向dragFlags中添加left和 right方向。
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
但是,对于grid而言,滑动删除不是非常自然的设计,因此你可能需要这样来去掉此功能:
@Override
public int getMovementFlags(RecyclerView recyclerView,
RecyclerView.ViewHolder viewHolder) {
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN |
ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
int swipeFlags = 0;
return makeMovementFlags(dragFlags, swipeFlags);
}
效果:
自定义滑动动画
ItemTouchHelper.Callback 提供了非常方便的方法来控制拖拽和滑动期间的view动画。因为ItemTouchHelper其实是一个RecyclerView.ItemDecoration,我可以
用同样的方式进行view的绘制。
在后面的部分,我们将更深入的讨论这个问题,但是这里也给出一个简单的例子,重写默认的滑动动画,显示线性淡化效果。
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {float width = (float) viewHolder.itemView.getWidth();float alpha = 1.0f - Math.abs(dX) / width;viewHolder.itemView.setAlpha(alpha);viewHolder.itemView.setTranslationX(dX); } else {super.onChildDraw(c, recyclerView, viewHolder, dX, dY,
actionState, isCurrentlyActive);
}
}
dX 与 dY参数代表目前被选择view 的移动距离,其中:
•-1.0f is a full ItemTouchHelper.END to ItemTouchHelper.STARTswipe
•1.0f is a full ItemTouchHelper.START to ItemTouchHelper.END swipe
为了不漏掉我们没有处理的actionState,记住务必调用super方法,这样其他的默认动画才会运行。
Android进阶七:RecyclerView拖动滑动之ItemTouchHelper相关推荐
- 【Android 事件分发】ItemTouchHelper 简介 ( 拖动/滑动事件 | ItemTouchHelper.Callback 回调 )
Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...
- Android进阶:RecyclerView中DiffUtil的使用
本文转载自:https://blog.csdn.net/zxt0601/article/details/52562770 一.概述 DiffUtil是support-v7:24.2.0中的新工具类,它 ...
- android 全局缓存,【Android进阶】RecyclerView之缓存(二)
前言 上一篇,说了ItemDecoration,这一篇,我们来说说RecyclerView的回收复用逻辑. 问题 假如有100个item,首屏最多展示2个半(一屏同时最多展示4个),RecyclerV ...
- Android Scrollview嵌套RecyclerView导致滑动卡顿问题解决(屡试不爽)
今天开发的一个项目首页,布局还是比较复杂的,各种滑动冲突,(Banner+横向RecyclerView+纵向RecyclerView(item又是横向的RecyclerView)), 最外面的框架用 ...
- 【RecyclerView】 十五、使用 ItemTouchHelper 实现 RecyclerView 拖动排序 ( ItemTouchHelper 简介 )
文章目录 一.ItemTouchHelper 简介 二.RecyclerView 相关资料 一.ItemTouchHelper 简介 官方文档 : https://developer.android. ...
- android歌词跟随手势滑动,Android实现跟随手指拖动并自动贴边的View样式(实例demo)...
效果图 代码 /** * 根据手指拖动的当前位置,自动贴边的View */ public class DragView extends ImageView implements View.OnTouc ...
- Android --- RecyclerView 水平滑动时,一个 item 一个 item 的滑动,禁止滑动到一半停止
使用RecyclerView水平滑动显示item,一个item占整个屏幕宽度, 所以基本写法水平滑动不会一个item一个item的显示完整,而是各自显示一部分.因此这个不是我们想要的结果.效果就是像广 ...
- Android之解决ScrollView包裹了两个RecyclerView导致滑动冲突问题
1 问题 ScrollView包裹了两个RecyclerView导致滑动冲突问题 2 解决办法 给ScrollView和两个RecyclerView分别设置isNestedScrollingEnabl ...
- android onscrolllistener判断到底部,判断RecyclerView是否滑动到底部
判断RecyclerView是否滑动到底部 recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Overri ...
最新文章
- JBoss 系列八十: jBPM 6 中使用 jbpm-console 创建执行 BPM 流程 - I
- mysql sql 1到10_(1.10)SQL优化——mysql 常见SQL优化
- 14.Python抠图脚本
- 「 每日一练,快乐水题 」504. 七进制数
- 【hadoop】1.简介
- “对技术没有好奇心”真的是很失败的一件事情
- 课程范例 20150916html1 练习
- Ehab and another construction problem(水题)
- python查看CNN训练模型参数
- arcgis加载dwg显示一个点_Arcgis添加控制点配准校正影像,更新校正之后,其他软件打开之后,影像位置没有校正解决办法...
- WebRTC促进跨平台指挥调度,触发安防应用新创意
- ssm-学子商城-项目第六天
- 《STM32》F103C8T6最小系统
- 中国省市县地区代码一览表
- android 仿qq 功能,Android仿QQ、新浪相册的实现
- elasticsearch-es search 查询
- java秒表程序_运用Java编写 秒表程序
- ORACLE EXP命令
- 实验四 MIPS寄存器文件设计 Logisim
- C++设计模式 | 四种创建型模式——简单工厂模式、工厂方法模式、抽象工厂模式、单例模式...
热门文章
- Cocos Creator 判断Touch位置在节点(Node)内
- 4128----喵帕斯之矩阵 sdut oj
- 《剑来》经典语录摘抄
- bluedroid key miss问题
- 2021级天梯赛 2.1-2.4
- ios上编译c语言的app_CppCode –适用于IOS的免费C / C ++ IDE和编译器
- python 奶茶系统2.0
- 机器学习讲座总结-读图时代的识图技术-车库咖啡
- 猎杀对决计算机丢失进不去,猎杀对决代码错误怎么解决 无法进入游戏解决方法...
- 这本书能让你减肥/戒烟/工作脱困/摆脱债务/重掌生活