recycleView 滑动删除Item,拖拽切换Item,你想了解的都在这儿
2016-12-29 08:35
489 查看
滑动删除Item,拖拽切换Item,你想了解的都在这儿
概述
如果上两篇对RecyclerView介绍后,依然没有引起你的兴趣,那么下面关于RecyclerView的使用我相信一定会让你如获珍宝。直接看运行效果。![](http://upload-images.jianshu.io/upload_images/354846-4f6693aa7bdf906a.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/240)
RecyclerView滑动删除.gif
![](http://upload-images.jianshu.io/upload_images/354846-3b0832652dc61e5b.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/240)
RecyclerView拖拽切换.gif
用ListView或者GridView实现上图中的功能非常麻烦,而如果用RecyclerView来实现,则非常简单。
如果对RecyclerView还没有认识的同学,可以查看这两篇文章。
RecyclerView使用一
RecyclerView使用二
ItemTouchHelper&ItemToucheHelper.CallBack
要实现上面的效果,代码很简单,只需要添加以下代码。mItemTouchHelper = new ItemTouchHelper(mItemTouchCallBack); mItemTouchHelper.attachToRecyclerView(mRecyclerView);
ItemTouchHelper主要用于对RecyclerView滑动删除和拖拽切换提供支持,它支持所有的类型的布局管理器LayoutManager。它只有一个构造函数,必须传入
ItemToucheHelper.CallBack这个类的实例化对象。
ItemToucheHelper.CallBack它可以控制用户的哪些行为是可以操控列表的Item的,当用户进行了这些操作,它会收到回调。它有几个重要的回调方法。
mItemTouchCallBack = new ItemTouchHelper.Callback() { /** * 设置滑动类型标记 * * @param recyclerView * @param viewHolder * @return * 返回一个整数类型的标识,用于判断Item那种移动行为是允许的 */ @Override public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { return makeMovementFlags(0,ItemTouchHelper.START | ItemTouchHelper.END); } /** * Item是否支持长按拖动 * * @return * true 支持长按操作 * false 不支持长按操作 */ @Override public boolean isLongPressDragEnabled() { return false; } /** * Item是否支持滑动 * * @return * true 支持滑动操作 * false 不支持滑动操作 */ @Override public boolean isItemViewSwipeEnabled() { return true; } /** * 拖拽切换Item的回调 * * @param recyclerView * @param viewHolder * @param target * @return * 如果Item切换了位置,返回true;反之,返回false */ @Override public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { return true; } /** * 滑动删除Item * * @param viewHolder * @param direction * Item滑动的方向 */ @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { mAdapter.delete(viewHolder.getAdapterPosition()); } /** * Item被选中时候回调 * * @param viewHolder * @param actionState * 当前Item的状态 * ItemTouchHelper.ACTION_STATE_IDLE 闲置状态 * ItemTouchHelper.ACTION_STATE_SWIPE 滑动中状态 * ItemTouchHelper#ACTION_STATE_DRAG 拖拽中状态 */ @Override public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { // item被选中的操作 if(actionState != ItemTouchHelper.ACTION_STATE_IDLE) { viewHolder.itemView.setBackgroundResource(R.color.md_gray); } super.onSelectedChanged(viewHolder, actionState); } /** * 移动过程中绘制Item * * @param c * @param recyclerView * @param viewHolder * @param dX * X轴移动的距离 * @param dY * Y轴移动的距离 * @param actionState * 当前Item的状态 * @param isCurrentlyActive * 如果当前被用户操作为true,反之为false */ @Override public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { float x = Math.abs(dX) + 0.5f; float width = viewHolder.itemView.getWidth(); float alpha = 1f - x / width; viewHolder.itemView.setAlpha(alpha); super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); } /** * 移动过程中绘制Item * * @param c * @param recyclerView * @param viewHolder * @param dX * X轴移动的距离 * @param dY * Y轴移动的距离 * @param actionState * 当前Item的状态 * @param isCurrentlyActive * 如果当前被用户操作为true,反之为false */ @Override public void onChildDrawOver(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { super.onChildDrawOver(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); } /** * 用户操作完毕或者动画完毕后会被调用 * * @param recyclerView * @param viewHolder */ @Override public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { // 操作完毕后恢复颜色 viewHolder.itemView.setBackgroundResource(R.color.md_white); viewHolder.itemView.setAlpha(1.0f); super.clearView(recyclerView, viewHolder); } };
可以看见,其实用户的行为都被官方提供的v7包给封装了一层,只暴露出几个重要的方法,也就是说滑动删除和拖拽切换主要的操作行为都在
ItemToucheHelper.CallBack中,我们主要关注它就行了。
滑动删除
RecyclerView的具体使用就不再次贴代码了,不清楚的同学可以查看RecyclerView使用这篇文章。看一下滑动删除的ItemToucheHelper.CallBack的实现。
mItemTouchCallBack = new ItemTouchHelper.Callback() { /** * 设置滑动类型标记,可从两端滑动Item */ @Override public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { return makeMovementFlags(0,ItemTouchHelper.START | ItemTouchHelper.END); } /** * 设置Item不支持长按拖动 */ @Override public boolean isLongPressDragEnabled() { return false; } /** * Item支持滑动 */ @Override public boolean isItemViewSwipeEnabled() { return true; } /** * 滑动删除Item的操作 */ @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { mAdapter.delete(viewHolder.getAdapterPosition()); } /** * Item被选中时候,改变Item的背景 */ @Override public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { // item被选中的操作 if(actionState != ItemTouchHelper.ACTION_STATE_IDLE) { viewHolder.itemView.setBackgroundResource(R.color.md_gray); } super.onSelectedChanged(viewHolder, actionState); } /** * 移动过程中重新绘制Item,随着滑动的距离,设置Item的透明度 */ @Override public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { float x = Math.abs(dX) + 0.5f; float width = viewHolder.itemView.getWidth(); float alpha = 1f - x / width; viewHolder.itemView.setAlpha(alpha); super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); } /** * 用户操作完毕或者动画完毕后调用,恢复item的背景和透明度 */ @Override public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { // 操作完毕后恢复颜色 viewHolder.itemView.setBackgroundResource(R.color.md_white); viewHolder.itemView.setAlpha(1.0f); super.clearView(recyclerView, viewHolder); } };
在
getMovementFlags()方法中,调用了一个已经有的方法
makeMovementFlags(int dragFlags, int swipeFlags),它用于创建一个滑动类型标记,有两个参数,第一个参数是拖拽的标记,第二个参数是滑动的标记。在这里我设置不可拖拽Item(传入0),可滑动Item的两端。
isLongPressDragEnabled返回了false,让Item不会触发长按事件。
isItemViewSwipeEnabled()返回了true,让Item支持滑动操作。
在
onSelectedChanged()方法中当Item的状态为滑动或者拖拽时候,改变Item背景。
在
onChildDraw()方法中处理了Item滑动操作,首先根据滑动距离改变了Item的透明度,然后调用父类方法,让Item根据手势滑动。
在
clearView()中,恢复了Item的背景和透明度。
在
onSwiped()方法中,调用自定的Adapter中的
delete()方法,将该位置的数据删除,并重新绘制列表。
public void delete(int position) { if(position < 0 || position > getItemCount()) { return; } mData.remove(position); notifyItemRemoved(position); }
最后实现的效果如下图。
![](http://upload-images.jianshu.io/upload_images/354846-4f6693aa7bdf906a.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/320)
RecyclerView滑动删除.gif
拖拽切换
拖拽切换和滑动删除思路相同,只不过在处理过程有一些不同。网易新闻在添加栏目时候,就有网格的列表,长按之后可以拖拽切换Item,可以参考一下,也做个类似的demo。先看下ItemToucheHelper.CallBack的实现。
mItemTouchCallBack = new ItemTouchHelper.Callback() { /** * 设置滑动类型标记 * * @param recyclerView * @param viewHolder * @return * 返回一个整数类型的标识,用于判断Item那种移动行为是允许的 */ @Override public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { return makeMovementFlags(ItemTouchHelper.RIGHT | ItemTouchHelper.LEFT | ItemTouchHelper.DOWN | ItemTouchHelper.UP, 0); } /** * Item是否支持长按拖动 * * @return * true 支持长按操作 * false 不支持长按操作 */ @Override public boolean isLongPressDragEnabled() { return true; } /** * Item是否支持滑动 * * @return * true 支持滑动操作 * false 不支持滑动操作 */ @Override public boolean isItemViewSwipeEnabled() { return false; } /** * 拖拽切换Item的回调 * * @param recyclerView * @param viewHolder * @param target * @return * 如果Item切换了位置,返回true;反之,返回false */ @Override public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { mAdapter.move(viewHolder.getAdapterPosition(), target.getAdapterPosition()); return true; } /** * Item被选中时候回调 * * @param viewHolder * @param actionState * 当前Item的状态 * ItemTouchHelper.ACTION_STATE_IDLE 闲置状态 * ItemTouchHelper.ACTION_STATE_SWIPE 滑动中状态 * ItemTouchHelper#ACTION_STATE_DRAG 拖拽中状态 */ @Override public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { // item被选中的操作 if(actionState != ItemTouchHelper.ACTION_STATE_IDLE) { viewHolder.itemView.setBackgroundResource(R.color.md_gray); } super.onSelectedChanged(viewHolder, actionState); } /** * 用户操作完毕或者动画完毕后会被调用 * * @param recyclerView * @param viewHolder */ @Override public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { // 操作完毕后恢复颜色 viewHolder.itemView.setBackgroundResource(R.drawable.md_common_bg); super.clearView(recyclerView, viewHolder); } };
getMovementFlags()中设置可上下左右拖拽Item,但是不能滑动Item。
isLongPressDragEnabled()设置为true,Item会出发长按事件
isItemViewSwipeEnabled()设置为false,Item不可滑动
onSelectedChanged()设置了Item被选中时候的背景
clearView()恢复了Item的背景
onMove()调用了自定义的Adapter中的
move()方法,将数据放到新的位置,并且重新绘制列表。
public void move(int fromPosition, int toPosition) { String prev = mData.remove(fromPosition); mData.add(toPosition > fromPosition ? toPosition - 1 : toPosition, prev); notifyItemMoved(fromPosition, toPosition); }
然后在设置RecyclerView的一些其他属性。
// 实例化ItemTouchHelperm mItemTouchHelper = new ItemTouchHelper(mItemTouchCallBack); // 实例化适配器 mAdapter = new MDDragRvAdapter(MDMockData.getRvData()); // 实例化布局管理器,网格样式 mLayoutManager = new GridLayoutManager(this, 4, OrientationHelper.VERTICAL, false); // 设置适配器 mRecyclerView.setAdapter(mAdapter); // 设置布局管理器 mRecyclerView.setLayoutManager(mLayoutManager); // 关联RecyclerView和ItemTouchHelper mItemTouchHelper.attachToRecyclerView(mRecyclerView);
最后看一下实现的效果。
![](http://upload-images.jianshu.io/upload_images/354846-3b0832652dc61e5b.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/320)
RecyclerView拖拽切换.gif
总结
在熟悉了ItemToucheHelper.CallBack后,就能根据自己的需求实现各种效果,列表或者网格的都可以满足,使用起来非常简单。关于RecyclerView使用的介绍,也到此为止了。最后附上Demo工程的地址。
Demo工程地址
相关文章推荐
- 详解javascript表单的Ajax提交插件的使用
- 1001害死人不偿命的(3n+1)猜想
- 充实的一天
- HTTPS 指南
- MySQL存储引擎中的MyISAM和InnoDB区别详解
- 关于autocomplete的小例子
- 基于javascript的Form表单验证
- 带你开发一款给Apk中自动注入代码工具icodetools(完善篇)
- 部署tensorflow后导入出现如下错误解决办法
- Action获取参数
- 线程池及并发编程基础总结
- JavaScript原型深入解析
- MySQL的隐式类型转换整理总结
- Spring中Bean的实例化
- Python interview_python
- 详解JS去重及字符串奇数位小写转大写
- Valid Sudoku
- Open Standards - a number of web pages for groups producing open standards
- android 四大组件介绍
- mysql主从、主主、分库、分表