Android进阶七:RecyclerView拖动滑动之ItemTouchHelper
来源:互联网 发布:flowchart软件 编辑:程序博客网 时间:2024/04/29 21:55
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:
@Overridepublic 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; } @Override public 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); } @Override public 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; } @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { mAdapter.onItemDismiss(viewHolder.getAdapterPosition()); } @Override public boolean isLongPressDragEnabled() { return true; } @Override public boolean isItemViewSwipeEnabled() { return true; } @Override public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) { ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder; //回调改变item的背景颜色 itemViewHolder.onItemSelected(); } super.onSelectedChanged(viewHolder, actionState); } @Override public 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 @Override public void onItemMove(int fromPosition, int toPosition) { String prev = mItems.remove(fromPosition); mItems.add(toPosition > fromPosition ? toPosition - 1 : toPosition, prev); notifyItemMoved(fromPosition, toPosition); } //删除item @Override public 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,改变背景颜色 @Override public void onItemSelected() { itemView.setBackgroundColor(Color.LTGRAY); } //放开item,改变背景颜色 @Override public 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; @Override public void onBindViewHolder(final RecyclerListAdapter.ItemViewHolder holder, int position) { holder.textView.setText(mItems.get(position)); holder.handleView.setOnTouchListener(new View.OnTouchListener() { @Override public 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 { …… @Override public void onStartDrag(RecyclerView.ViewHolder viewHolder) { mItemTouchHelper.startDrag(viewHolder); } ……}
效果:
Grid 布局
如果你想用GridLayoutManager来修改这个项目,你会发现不能正常工作。原因和解决办法都很简单:我们必须告诉ItemTouchHelper我们想支持向左拖动和向右拖动。在InSimpleItemTouchHelperCallback中,我们已经指明了:
@Overridepublic 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而言,滑动删除不是非常自然的设计,因此你可能需要这样来去掉此功能:
@Overridepublic 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的绘制。
在后面的部分,我们将更深入的讨论这个问题,但是这里也给出一个简单的例子,重写默认的滑动动画,显示线性淡化效果。
@Overridepublic 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
- RecyclerView借助ItemTouchHelper实现拖动和滑动删除功能
- ItemTouchHelper实现RecyclerView拖动排序和滑动删除
- RecyclerView之ItemTouchHelper仿今日头条频道管理拖动
- Android使用ItemTouchHelper实现RecyclerView的item拖动位置交换
- RecyclerView爱恨情仇之ItemTouchHelper
- RecyclerView的拖动和滑动 第一部分 :基本的ItemTouchHelper示例
- RecyclerView的拖动和滑动 第一部分 :基本的ItemTouchHelper示例
- RecyclerView的拖动和滑动:基本的ItemTouchHelper示例(转)
- RecyclerView的拖动和滑动 第一部分 :基本的ItemTouchHelper示例
- RecyclerView+ItemTouchHelper实现拖拽滑动
- android之RecycleView之ItemTouchHelper 处理拖拽、滑动删除
- Android进阶之RecyclerView
- RecyclerView ItemTouchHelper
- RecyclerView长按拖动效果,用ItemTouchHelper实现
- Android进阶之RecyclerView使用
- RecyclerView之使用ItemTouchHelper实现交互动画
- Android ItemTouchHelper实现RecyclerView交互动画
- 第十五周训练总结(二)
- MyEclipse使用Ant打包项目
- JSP中的EL表达式详细介绍
- JSPerf-javascript代码性能测试利器
- 写策略做回测
- Android进阶七:RecyclerView拖动滑动之ItemTouchHelper
- navicate导入数据
- 彻底搞懂CNN
- python写入mysql中datetime类型遇到的问题
- LA 3644 X-Plosives
- DUBBO简介及使用
- SSH 登录时出现公钥失效错误
- 前端安全性问题
- Linux下的目录权限以及进行增删查改等文件操作时需要的权限