recycleView的位置調換和側滑刪除
轉載:https://blog.csdn.net/Android_Study_OK/article/details/51545172
效果圖
參考
RecyclerView的拖動和滑動 第一部分 :基本的ItemTouchHelper示例
概述:
ItemTouchHelperAdapter:(★)
RecyclerListAdapter需要實現這個介面,
RecyclerListAdapter通過ItemTouchHelperAdapter的onItemMove和onItemDismiss方法來完成條目移動、條目消除的操作,並且通過notifyItemMoved()和notifyItemRemoved()來通知adapter資料的改變
ItemTouchHelperViewHolder:(★)
RecyclerListAdapter的內部類ItemViewHolder需要實現這個介面ItemViewHolder,通過呼叫ItemTouchHelperViewHolder的onItemSelected()和onItemClear()來完成條目被選中時(底色變灰色)、條目動畫完成時(底色變透明)的操作
SimpleItemTouchHelperCallback:(★★★★★)
該類繼承於抽象類ItemTouchHelper.Callback,ItemTouchHelper.Callback已經封裝了RecyclerView拖動、側滑的效果,我們只需要重寫其暴露出來的方法來控制拖拽即可,具體涉及到的方法有:(詳細介紹見原始碼)
1. 建構函式
2.
isLongPressDragEnabled()
3.
isItemViewSwipeEnabled()
4.
getMovementFlags()
5.
onMove()
6.
onSwiped()
7.
onSelectedChanged()
8.
clearView()
MainActivity/RecyclerListFragment(★)
外界如何呼叫
RecyclerListAdapter(★★★★★)
-
該類實現了ItemTouchHelperAdapter介面
RecyclerListAdapter通過ItemTouchHelperAdapter的onItemMove和onItemDismiss方法來完成條目移動、條目消除的操作,並且通過notifyItemMoved()和notifyItemRemoved()來通知adapter資料的改變
-
其內部類ItemViewHolder實現這個介面ItemTouchHelperViewHolder
通過呼叫ItemTouchHelperViewHolder的onItemSelected()和onItemClear()來完成條目被選中時(底色變灰色)、條目動畫完成時(底色變透明)的操作
外部使用Activity/Fragment
package co.paulburke.android.itemtouchhelperdemo;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import co.paulburke.android.itemtouchhelperdemo.helper.SimpleItemTouchHelperCallback;
/**
* @author Paul Burke (ipaulpro)
*/
public class RecyclerListFragment extends Fragment {
private ItemTouchHelper mItemTouchHelper;
public RecyclerListFragment() {
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_main, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// ★★★關鍵之處在於RecyclerListAdapter的寫法
RecyclerListAdapter adapter = new RecyclerListAdapter();
RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
// setHasFixedSize()方法用來使RecyclerView保持固定的大小,該資訊被用於自身的優化。
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
/**
* ★★★★★★★★★★★★★★★★★★★★★★★
* 要使用ItemTouchHelper,你需要建立一個ItemTouchHelper.Callback。
* 這個介面可以讓你監聽“move(上下移動)”與 “swipe(左右滑動)”事件。這裡還是
* ★控制view被選中
* 的狀態以及★重寫預設動畫的地方。
*
* 如果你只是想要一個基本的實現,有一個
* 幫助類可以使用:SimpleCallback,但是為了瞭解其工作機制,我們還是自己實現
*/
ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(adapter);
mItemTouchHelper = new ItemTouchHelper(callback);
// 將定義好的mItemTouchHelper應用於我們的recyclerView,使得recyclerView獲得move和swipe的效果
mItemTouchHelper.attachToRecyclerView(recyclerView);
}
}
- 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
SimpleItemTouchHelperCallback
package co.paulburke.android.itemtouchhelperdemo.helper;
import android.graphics.Canvas;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
/**
* An implementation of {@link ItemTouchHelper.Callback} that enables basic drag & drop and
* swipe-to-dismiss. Drag events are automatically started by an item long-press.<br/>
* </br/>
* Expects the <code>RecyclerView.Adapter</code> to react to {@link
* ItemTouchHelperAdapter} callbacks and the <code>RecyclerView.ViewHolder</code> to implement
* {@link ItemTouchHelperViewHolder}.
*
* 接下來的兩個是onMove()和onSwiped(),用於通知底層資料的更新。
*
* @author Paul Burke (ipaulpro)
*/
public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
private final ItemTouchHelperAdapter mAdapter;
public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {
mAdapter = adapter;
}
/**
* 要支援長按RecyclerView item進入拖動操作,
* 你必須在isLongPressDragEnabled()方法中返回true。
* 或者,也可以呼叫ItemTouchHelper.startDrag(RecyclerView.ViewHolder)
* 方法來開始一個拖動。
*/
@Override
public boolean isLongPressDragEnabled() {
return true;//返回true表示支援長按開始拖拽
}
/**
* 而要在view任意位置觸控事件發生時啟用滑動操作,
* 則直接在sItemViewSwipeEnabled()中返回true就可以了。
* 或者,你也主動呼叫ItemTouchHelper.startSwipe(RecyclerView.ViewHolder)
* 來開始滑動操作。
*/
@Override
public boolean isItemViewSwipeEnabled() {
return true;//返回true表示支援左右滑動
}
/**
* ItemTouchHelper可以讓你輕易得到一個事件的方向。
* 你需要重寫getMovementFlags()方法來指定可以支援
* 的拖放和滑動的方向。
* 使用helperItemTouchHelper.makeMovementFlags(int, int)
* 來構造返回的flag。這裡我們啟用了上下左右兩種方向。
* 注:上下為拖動(drag),左右為滑動(swipe)。
*/
@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);//表示支援上下拖拽和左右滑動
// return makeMovementFlags(dragFlags, 0);//第二項為0,表示你支援拖拽,不支援左右滑動
}
/**
* Called when ItemTouchHelper wants to move the dragged item from its old position to
* the new position.
* 當移動一個條目時被呼叫
* <p>
* If this method returns true, ItemTouchHelper assumes {@code viewHolder} has been moved
* to the adapter position of {@code target} ViewHolder
* ({@link RecyclerView.ViewHolder#getAdapterPosition()
* ViewHolder#getAdapterPosition()}).
* 如果該方法返回true,認定條目已經移動到了新的位置
* <p>
* If you don't support drag & drop, this method will never be called.
* 如果你不支援拖拽,此方法不會被呼叫
*
* @param recyclerView The RecyclerView to which ItemTouchHelper is attached to.
* ItemTouchHelper所附著的RecyclerView
* @param source The ViewHolder which is being dragged by the user.
* 正在被使用者拖拽的位置
* @param target The ViewHolder over which the currently active item is being
* dragged.
* 當前正在被拖拽的條目所經過的位置
* @return True if the {@code viewHolder} has been moved to the adapter position of
* {@code target}.
* @see #onMoved(RecyclerView, RecyclerView.ViewHolder, int, RecyclerView.ViewHolder, int, int, int)
*/
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
mAdapter.onItemMove(source.getAdapterPosition(), target.getAdapterPosition());
return true;
}
/**
* Called when a ViewHolder is swiped by the user.
* 當被左右滑動時,呼叫該方法
* 注意:這裡的ViewHolder統一翻譯成條目,通過ViewHolder可以得到關於條目的所有屬性(如:位置等等)
* <p>
* If you are returning relative directions ( {START} , {END}) from the
* {@link #getMovementFlags(RecyclerView, RecyclerView.ViewHolder)} method, this method
* will also use relative directions. Otherwise, it will use absolute directions.
* 當你返回一個相對方向時(由getMovementFlags()所返回的方向),該方法使用的是相對方向,否則使用絕對方向
* <p>
* If you don't support swiping, this method will never be called.
* 如果你不支援左右滑動,該方法不會被呼叫
* <p>
* ItemTouchHelper will keep a reference to the View until it is detached from
* RecyclerView.
* ItemTouchHelper將會持有View的引用,直到ItemTouchHelper不再附著在RecyclerView上時
* As soon as it is detached, ItemTouchHelper will call
* {@link #clearView(RecyclerView, RecyclerView.ViewHolder)}.
* 當不再附著時,ItemTouchHelper會呼叫clearView方法
*
* @param viewHolder The ViewHolder which has been swiped by the user.
* 使用者拖拽的條目
* @param direction The direction to which the ViewHolder is swiped. It is one of
* {UP}, {DOWN},
* {LEFT} or {RIGHT}. If your
* {@link #getMovementFlags(RecyclerView, RecyclerView.ViewHolder)}
* method
* returned relative flags instead of {LEFT} / {RIGHT};
* `direction` will be relative as well. ({START} or {
* END}).
* 條目被左右滑動的方向,他是上、下、左、右中的一個,如果getMovementFlags返回了
* 相對標誌flags代替了左、右方向,將使用這個返回的方向
*
*/
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
}
/**
* Called when the ViewHolder swiped or dragged by the ItemTouchHelper is changed.
* 當條目被改變(拖拽、側滑)時,該方法被呼叫
* <p/>
* If you override this method, you should call super.
* 如果你重寫該方法,你應該呼叫super
*
* @param viewHolder The new ViewHolder that is being swiped or dragged. Might be null if
* it is cleared.
* 正在被拖拽/側滑的條目,可能為null,如果他被清除掉
* @param actionState One of {@link ItemTouchHelper#ACTION_STATE_IDLE},
* {@link ItemTouchHelper#ACTION_STATE_SWIPE} or
* {@link ItemTouchHelper#ACTION_STATE_DRAG}.
* 活動狀態:空閒、側滑、拖拽,根據這個判斷不同狀態下的操作
*
* @see #clearView(RecyclerView, RecyclerView.ViewHolder)
*/
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {//只要這個條目不是空閒狀態(即:拖拽或者側滑)
ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
itemViewHolder.onItemSelected();//這裡改變選中時的條目的狀態
}
super.onSelectedChanged(viewHolder, actionState);
}
/**
* Called by the ItemTouchHelper when the user interaction with an element is over and it
* also completed its animation.
* 當ItemTouchHelper已經完成他的動畫時(即使用者與條目互動完成後),該方法被呼叫
* <p>
* This is a good place to clear all changes on the View that was done in
* {@link #onSelectedChanged(RecyclerView.ViewHolder, int)},
* {@link #onChildDraw(Canvas, RecyclerView, RecyclerView.ViewHolder, float, float, int,
* boolean)} or
* {@link #onChildDrawOver(Canvas, RecyclerView, RecyclerView.ViewHolder, float, float, int, boolean)}.
* 這是一個很好的地方,用來清除所有條目動畫完成後的效果(可能你在onSelectedChanged()、onChildDraw()
* onChildDrawOver()時賦予了條目很多效果,在這個方法裡,統統把這些效果清除掉)
*
* @param recyclerView The RecyclerView which is controlled by the ItemTouchHelper.
* @param viewHolder The View that was interacted by the user.
*/
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
itemViewHolder.onItemClear();//在這裡處理清除掉條目效果
}
}
- 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
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
ItemTouchHelperAdapter
package co.paulburke.android.itemtouchhelperdemo.helper;
import android.support.v7.widget.RecyclerView;
/**
* Interface to notify a {@link RecyclerView.Adapter} of moving and dismissal event from a {@link
* android.support.v7.widget.helper.ItemTouchHelper.Callback}.
*
* @author Paul Burke (ipaulpro)
*/
public interface ItemTouchHelperAdapter {
/**
* Called when an item has been dragged far enough to trigger a move. This is called every time
* an item is shifted, and not at the end of a "drop" event.
*
*當一個條目被拖拽移動時,該方法將被呼叫,當條目被移動時,該方法都會被呼叫,而不是在拖拽結尾才被呼叫
*
* @param fromPosition The start position of the moved item.
* @param toPosition Then end position of the moved item.
* @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder)
* @see RecyclerView.ViewHolder#getAdapterPosition()
*/
void onItemMove(int fromPosition, int toPosition);
/**
* Called when an item has been dismissed by a swipe.
*
* 當左右滑動條目時,呼叫該方法
*
* @param position The position of the item dismissed.
* @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder)
* @see RecyclerView.ViewHolder#getAdapterPosition()
*/
void onItemDismiss(int position);
}
- 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
ItemTouchHelperViewHolder
package co.paulburke.android.itemtouchhelperdemo.helper;
import android.support.v7.widget.helper.ItemTouchHelper;
/**
* Interface to notify an item ViewHolder of relevant callbacks from {@link
* android.support.v7.widget.helper.ItemTouchHelper.Callback}.
*
* @author Paul Burke (ipaulpro)
*/
public interface ItemTouchHelperViewHolder {
/**
* Called when the {@link ItemTouchHelper} first registers an item as being moved or swiped.
* Implementations should update the item view to indicate it's active state.
* 當ItemTouchHelper將拖拽/側滑註冊(作用)到條目上時,實現該方法去更新這個條目的檢視效果,
* 以暗示該條目正在被操作
*
*/
void onItemSelected();
/**
* Called when the {@link ItemTouchHelper} has completed the move or swipe, and the active item
* state should be cleared.
* 當ItemTouchHelper完成了拖拽/側滑時,啟用的條目效果應該被消除
*/
void onItemClear();
}
- 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
主要的程式碼:RecyclerListAdapter
package co.paulburke.android.itemtouchhelperdemo;
import android.graphics.Color;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import co.paulburke.android.itemtouchhelperdemo.helper.ItemTouchHelperAdapter;
import co.paulburke.android.itemtouchhelperdemo.helper.ItemTouchHelperViewHolder;
/**
* @author Paul Burke (ipaulpro)
* ★ RecyclerListAdapter要實現ItemTouchHelperAdapter
* 重寫onItemDismiss(刪除條目)和onItemMove(移動條目)
*
* ★ RecyclerView.ViewHolder實現ItemTouchHelperViewHolder
* 重寫onItemSelected(條目被選中時)和onItemClear(條目被拖拽之後)
*/
public class RecyclerListAdapter extends RecyclerView.Adapter<RecyclerListAdapter.ItemViewHolder>
implements ItemTouchHelperAdapter {
private static final String[] STRINGS = new String[]{
"One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten"
};
private final List<String> mItems = new ArrayList<>();
public RecyclerListAdapter() {
mItems.addAll(Arrays.asList(STRINGS));
}
@Override
public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_main, parent, false);
ItemViewHolder itemViewHolder = new ItemViewHolder(view);
return itemViewHolder;
}
@Override
public void onBindViewHolder(final ItemViewHolder holder, int position) {
holder.textView.setText(mItems.get(position));
}
// 當條目被刪除時的操作(實現ItemTouchHelperAdapter重寫onItemDismiss方法)
@Override
public void onItemDismiss(int position) {
mItems.remove(position);
// 通知條目已經被刪除,與adapter互動
notifyItemRemoved(position);
}
// 當條目被移動時的操作(實現ItemTouchHelperAdapter重寫onItemMove方法)
@Override
public void onItemMove(int fromPosition, int toPosition) {
// ★移動一個條目分兩步:首先把該條目先移除,再考慮在對應要移動到的地方增加這個條目
String prev = mItems.remove(fromPosition);
// toPosition > fromPosition ? toPosition - 1 : toPosition,
// 即將拖動到的位置是否比開始拖動的位置大,
// 如果大,則在集合裡在toPosition - 1處填寫該條目,否則在toPosition處新增該條目
mItems.add(toPosition > fromPosition ? toPosition - 1 : toPosition, prev);
// 通知條目被移動,與adapter互動
notifyItemMoved(fromPosition, toPosition);
}
@Override
public int getItemCount() {
return mItems.size();
}
public static class ItemViewHolder extends RecyclerView.ViewHolder implements
ItemTouchHelperViewHolder {
public final TextView textView;
public ItemViewHolder(View itemView) {
super(itemView);
textView = (TextView) itemView;
}
@Override
public void onItemSelected() {
// 當選中時,背景色為灰色
itemView.setBackgroundColor(Color.LTGRAY);
}
@Override
public void onItemClear() {
// 當拖拽完畢後,背景色為透明
itemView.setBackgroundColor(0);
}
}
}
- 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