今天和大家一起实现RecyclerView可拖拽Item,主要是使用RecyclerView结合ItemTouchHelper来实现的
这个类在v7包里面
实现步骤:
1.只需要给recyclerView添加一个ItemTouchHelper对象就行
mItemTouchHelper =
new
ItemTouchHelper(
new
ItemTouchHelper.Callback() );
mItemTouchHelper.attachToRecyclerView(mRecyclerView);
2.ItemTouchHelper的callback
首先来自定义一个CallBack类,继承与ItemTouchHepler.Callback()对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
}
|
1).首先说一下getMovementFlags(),
这个方法是设置是否滑动时间,以及拖拽的方向,所以在这里需要判断一下是列表布局还是网格布局,
如果是列表布局的话则拖拽方向为DOWN和UP,如果是网格布局的话则是DOWN和UP和LEFT和RIGHT,对应这个方法的代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
if (recyclerView.getLayoutManager() instanceof GridLayoutManager) {
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN |
ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
final int swipeFlags = 0 ;
return makeMovementFlags(dragFlags, swipeFlags);
} else {
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
final int swipeFlags = 0 ;
return makeMovementFlags(dragFlags, swipeFlags);
}
}
|
2).而onMove()方法则是我们在拖动的时候不断回调的方法,在这里我们需要将正在拖拽的item和集合的item进行交换元素,然后在通知适配器更新数据,也很简单,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
//得到当拖拽的viewHolder的Position
int fromPosition = viewHolder.getAdapterPosition();
//拿到当前拖拽到的item的viewHolder
int toPosition = target.getAdapterPosition();
if (fromPosition < toPosition) {
for ( int i = fromPosition; i < toPosition; i++) {
Collections.swap(datas, i, i + 1 );
}
} else {
for ( int i = fromPosition; i > toPosition; i--) {
Collections.swap(datas, i, i - 1 );
}
}
myAdapter.notifyItemMoved(fromPosition, toPosition);
return true ;
}
|
3).onSwiped()是替换后调用的方法,可以不用管。然后我们希望在拖拽的时候将被拖拽的Item高亮,这样用户体验要好很多,所以我们要重写CallBack对象中的onSelectedChanged()和clearView()方法,在选中的时候设置高亮背景色,在完成的时候移除高亮背景色,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
/**
* 长按选中Item的时候开始调用
*
* @param viewHolder
* @param actionState
*/
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
viewHolder.itemView.setBackgroundColor(Color.LTGRAY);
}
super .onSelectedChanged(viewHolder, actionState);
}
/**
* 手指松开的时候还原
* @param recyclerView
* @param viewHolder
*/
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super .clearView(recyclerView, viewHolder);
viewHolder.itemView.setBackgroundColor( 0 );
}
|
这样就实现了我们的基本要求,但是实际功能中有可能存在,排头前两个的不需改变它的顺序,即有些item允许拖拽,有些则不允许,所以我们需要重写isLongPressDragEnabled()设置不允许长按拖拽
1
2
3
4
5
6
7
8
|
/**
* 重写拖拽不可用
* @return
*/
@Override
public boolean isLongPressDragEnabled() {
return false ;
}
|
然后在重写RecycleView的长按监听(这个要自己写个接口去实现),在返回的长按方法中判断是否为不可拖拽的item,若不是,则调用ItemTouchHelper的startDrag()方法,逻辑出入如下:
1
2
3
4
5
6
7
8
|
@Override
public void onItemLongClick(RecyclerView.ViewHolder vh) {
//判断被拖拽的是否是前两个,如果不是则执行拖拽
if (vh.getLayoutPosition() != 0 && vh.getLayoutPosition() != 1 ) {
mItemTouchHelper.startDrag(vh);
}
}
|
5.重要的拖动之后,数据变了。Adapter中实现下面的接口
RecyclerView.Adapter
@Override
public void onMove(int fromPosition, int toPosition) {
/**
* 在这里进行给原数组数据的移动
*/
Collections.swap(mData, fromPosition, toPosition);
/**
* 通知数据移动
*/
notifyItemMoved(fromPosition, toPosition);
}