您的位置:首页 > 其它

RecyclerView实现条目Item拖拽排序与滑动删除

2017-09-21 09:07 666 查看


1. 概述

如果上两篇对RecyclerView介绍后,依然没有引起你的兴趣,那么下面关于RecyclerView的使用我相信一定会让你如获珍宝。直接看运行效果。



图-1 RecyclerView滑动删除



图-2 RecyclerView拖拽切换

用ListView或者GridView实现上图中的功能非常麻烦,而如果用RecyclerView来实现,则非常简单。

如果对RecyclerView还没有认识的同学,可以查看这两篇文章。

RecyclerView使用一

RecyclerView使用二


2. ItemTouchHelper&ItemToucheHelper.CallBack

要实现上面的效果,代码很简单,只需要添加以下代码。
mItemTouchHelper = new ItemTouchHelper(mItemTouchCallBack);

mItemTouchHelper.attachToRecyclerView(mRecyclerView);
1
2
3

       
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);
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147

       可以看见,其实用户的行为都被官方提供的v7包给封装了一层,只暴露出几个重要的方法,也就是说滑动删除和拖拽切换主要的操作行为都在
ItemToucheHelper.CallBack
中,我们主要关注它就行了。


3. 滑动删除

       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);
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

做了以下修改,说明一下各个方法的作用:
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);
}
1
2
3
4
5
6
7

最后实现的效果如下图。



图-3 RecyclerView滑动删除


4. 拖拽切换

       拖拽切换和滑动删除思路相同,只不过在处理过程有一些不同。网易新闻在添加栏目时候,就有网格的列表,长按之后可以拖拽切换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);
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85

做了以下的修改,说明一下各个方法的作用:
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);
}
1
2
3
4
5

然后在设置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);
1
2
3
4
5
6
7
8
9
10
11
12

最后看一下实现的效果。



图-4 RecyclerView拖拽切换


5. 总结

       在熟悉了
ItemToucheHelper.CallBack
后,就能根据自己的需求实现各种效果,列表或者网格的都可以满足,使用起来非常简单。关于RecyclerView使用的介绍,也到此为止了。最后附上Demo工程的地址。

最后附上工程地址:https://github.com/Kyogirante/MaterialDesignDemo
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: