一、前言 RecyclerView 第二篇。这篇主要将 RecyclerView 的拖动,滑动。
二、代码:
1、先看一下效果:
要想实现这样的效果,在Android support V7包下为我们提供了一个类:ItemTouchHelper 所有RecyclerView Item上下左右拖动,滑动删除均可以利用这个类实现。
2、首先需要自定义类实现ItemTouchHelper.Callback
package recyclerdemo.li.com.recyclerdemo.main;
import android.graphics.Canvas;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.util.Log;
/**
* Created lixin on 2016/4/27.
*/
public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
private ItemTouchHelperAdapter mItemTouchHelperAdapter;
public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter){
mItemTouchHelperAdapter = adapter;
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
//针对ListView的支持
int dragFlag = ItemTouchHelper.UP| ItemTouchHelper.DOWN;//上下拖动
int swipFlag = ItemTouchHelper.START|ItemTouchHelper.END;//左右滑动
//针对GridView的支持
// int dragFlag = ItemTouchHelper.UP|ItemTouchHelper.DOWN|ItemTouchHelper.START|ItemTouchHelper.END;
// int swipFlag = 0;
return makeMovementFlags(dragFlag,swipFlag);
}
/**
* 长按进入操作
* @return
*/
@Override
public boolean isLongPressDragEnabled() {
return true;
}
/**
* 用于支持滑动
* @return
*/
@Override
public boolean isItemViewSwipeEnabled() {
return true;
}
/**
* 移动
* @param recyclerView
* @param viewHolder
* @param target
* @return
*/
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
mItemTouchHelperAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
/**
* 移除
* @param viewHolder
* @param direction
*/
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
mItemTouchHelperAdapter.onItemDismiss(viewHolder.getAdapterPosition());
}
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView,
RecyclerView.ViewHolder viewHolder, float dX, float dY,
int actionState, boolean isCurrentlyActive) {
Log.d("test","dx : "+ dX +" dy : "+ dY);
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);
}
}
}
继承ItemTouchHelper.Callback 类需要重写一下几个方法:
(1)getMovementFlags()方法。
主要用于设置退拽以及滑动的方向。
//针对ListView的支持
int dragFlag = ItemTouchHelper.UP| ItemTouchHelper.DOWN;//上下拖动
int swipFlag = ItemTouchHelper.START|ItemTouchHelper.END;//左右滑动
//针对GridView的支持
int dragFlag = ItemTouchHelper.UP|ItemTouchHelper.DOWN|ItemTouchHelper.START|ItemTouchHelper.END;
int swipFlag = 0;
其中针对ListView,上下拖动,左右滑动删除。针对GridView排列方式,可以上下左右随意拖动,当swipFlag = 0 表示其不可以被滑动删除。
(2)isLongPressDragEnabled()返回True 表示长按进入操作。
(3)isItemViewSwipeEnabled()返回True表示支持滑动删除。
(4)onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target)
第二个参数viewHolder 表示被拖动的元素。第三个元素target即表示其目标元素。
(5)onSwiped()移除
(6)onChildDraw()当发生拖动以及移除操作时,会不断的调用这个参数。其中参数dX dY即表示被拖动的所对应XY的距离。可以用这个方法加入一些动画。
(7)其中 ItemTouchHelperAdapter 为自定义接口:
package recyclerdemo.li.com.recyclerdemo.main;
/**
* Created by lixin on 2016/4/27.
*/
public interface ItemTouchHelperAdapter {
void onItemMove(int fromPosition, int toPosition);
void onItemDismiss(int position);
}
在初始化SimpleItemTouchHelperCallback 时将其对象传入,用于在发生拖动以及删除时回调给Adapter,通知Adapter更新数据。
及我们自定义的Adapter需要实现ItemTouchHelperAdapter ,重写onItemMove ,onItemDismiss方法。
Adapter代码:
private class CustomAdapter extends RecyclerView.Adapter implements ItemTouchHelperAdapter {
private OnStartDragListener mOnStartDragListener;
public CustomAdapter(OnStartDragListener onStartDragListener){
this.mOnStartDragListener = onStartDragListener;
}
@Override
public int getItemCount() {
return mData.size();
}
@Override
public RecyclerHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerHolder holder = new RecyclerHolder(LayoutInflater.from(MainActivity.this).inflate(R.layout.recycler_item2,parent,false));
return holder;
}
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
final RecyclerHolder rholder = (RecyclerHolder)holder;
rholder.textView.setText(mData.get(position));
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public void onItemDismiss(int position) {
mData.remove(position);
notifyItemRemoved(position);
notifyDataSetChanged();
}
@Override
public void onItemMove(int fromPosition, int toPosition) {
Collections.swap(mData,fromPosition,toPosition);
notifyItemMoved(fromPosition,toPosition);
}
}
class RecyclerHolder extends RecyclerView.ViewHolder{
TextView textView;
Button button;
public RecyclerHolder(View view){
super(view);
textView = (TextView)view.findViewById(R.id.text);
button = (Button)view.findViewById(R.id.drag);
}
}
注意:在RecyclerView 中可以调用notifyItemInserted(int position)表示插入了一条元素,notifyItemRemoved(int position)表示有一条元素被删除了。其中position表示被加入以及删除的位置。而不再需要调用notifyDataSetChanged()方法。同样notifyItemMoved(int fromPosition,int toPosition);用于表示从哪个位置移动到了哪个位置。
3、在RecyclerView 初始化时:
//设置拖拽,移除
ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(mAdapter);
mItemTouchHelper = new ItemTouchHelper(callback);
mItemTouchHelper.attachToRecyclerView(mRecyclerView);
4、综上所诉便可以实现RecyclerView的滑动以及删除。
三、总结:
RecyclerView 实现拖动以及删除可以利用ItemTouchHelper ,轻轻松松便可以实现效果。而且看ItemTouchHelper 的源码发现其是继承自RecyclerView.ItemDecoration 的。RecyclerView.ItemDecoration前文提到过,是用于实现分割线的。这是不是很有意思呢。好了,今天就写到这,有哪些不足,或者错误之处,欢迎指正。令下一篇会写RecyclerView相关一些开源库,并且探讨一下开源库内部是如何实现的。
四、参考资料:
泡在网上的日子
https://medium.com/@ipaulpro/drag-and-swipe-with-recyclerview-b9456d2b1aaf