Android使用RecycleView實現拖拽交換item位置
阿新 • • 發佈:2018-11-20
本文例項為大家分享了RecycleView實現拖拽交換item位置的具體程式碼,供大家參考,具體內容如下
老規矩,先來一張效果圖:
相比起ListView而言,RecycleView實現拖拽交換位置的效果要簡單很多,因為通過SDK中的ItemTouchHelper工具類可以輕鬆的實現這種效果,並且一套程式碼支援所有佈局方式;而ListView的話則需要通過生成View的快取映象設定到ImageView中,然後通過WindowManager來操作該ImageView,具體怎麼實現這裡就不展開講解了.迴歸到ItemTouchHelper話題上,這個工具類我們需要關心的方法只有一個,即:
1 |
public
void
attachToRecyclerView(
@Nullable
RecyclerView recyclerView) {}
|
通過名字也可以知道其作用就是和RecyclerView 建立關係.
而我們真正需要關心的地方就是ItemTouchHelper的內部類ItemTouchHelper.Callback,它是一個抽象類,需要我們去實現下面這幾個關鍵的抽象方法以及重寫幾個非抽象的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
//決定拖拽/滑動的方向
public
abstract
int
getMovementFlags(RecyclerView recyclerView,
ViewHolder viewHolder);
//和位置交換有關,可用於實現drag功能
public
abstract
boolean
onMove(RecyclerView recyclerView,
ViewHolder viewHolder, ViewHolder target);
//和滑動有關,可用於實現swipe功能
public
abstract
void
onSwiped(ViewHolder viewHolder,
int
direction);
//是否長按啟用拖拽功能,預設是true
public
boolean
isLongPressDragEnabled() {
return
true
;}
//是否支援滑動,預設true
public
boolean
isItemViewSwipeEnabled() {
return
true
;}
//和目標View的狀態改變有關,例如drag,swipe,ide
public
void
onSelectedChanged(ViewHolder viewHolder,
int
actionState) {}
//和移除View的狀態有關,通常用於清除在onSelectedChanged,onChildDraw中對View設定的動畫
public
void
clearView(RecyclerView recyclerView, ViewHolder viewHolder) {}
|
當建立完ItemTouchHelper.Callback的實現類,我這裡稱之為SimpleItemTouchHelperCallback後,還需要將資料的變化以及View的狀態通知到RecycleView的Adapter中,為了達到解耦的目的,通常可以通過定義介面來實現,在SimpleItemTouchHelperCallback的構造方法中傳入該解耦介面的引用,並讓RecycleView的Adapter實現該解耦的介面,這樣就實現了這2個類的通訊問題了.
來看看我定義的解耦介面:
?1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
/**
* 定義RecycleView的Adapter和SimpleItemTouchHelperCallback直接互動的介面方法
* Created by mChenys on 2017/2/16.
*/
public
interface
ItemTouchHelperAdapter {
//資料交換
void
onItemMove(RecyclerView.ViewHolder source, RecyclerView.ViewHolder target);
//資料刪除
void
onItemDissmiss(RecyclerView.ViewHolder source);
//drag或者swipe選中
void
onItemSelect(RecyclerView.ViewHolder source);
//狀態清除
void
onItemClear(RecyclerView.ViewHolder source);
}
|
完整的SimpleItemTouchHelperCallback程式碼如下:
?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 4 |
/**
* 處理RecycleView的選中,拖拽移動,拖拽刪除的實現類
* Created by mChenys on 2017/2/16.
*/
public
class
SimpleItemTouchHelperCallback
extends
ItemTouchHelper.Callback {
private
ItemTouchHelperAdapter mAdapter;
public
SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {
mAdapter = adapter;
}
@Override
public
int
getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
//int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; //允許上下的拖動
//int dragFlags =ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; //允許左右的拖動
//int swipeFlags = ItemTouchHelper.LEFT; //只允許從右向左側滑
//int swipeFlags = ItemTouchHelper.DOWN; //只允許從上向下側滑
//一般使用makeMovementFlags(int,int)或makeFlag(int, int)來構造我們的返回值
//makeMovementFlags(dragFlags, swipeFlags)
int
dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
//允許上下左右的拖動
return
makeMovementFlags(dragFlags,
0
);
}
@Override
public
boolean
isLongPressDragEnabled() {
return
true
;
//長按啟用拖拽
}
@Override
public
boolean
isItemViewSwipeEnabled() {
return
false
;
//不啟用拖拽刪除
}
@Override
public
boolean
onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
//通過介面傳遞拖拽交換資料的起始位置和目標位置的ViewHolder
mAdapter.onItemMove(source, target);
return
true
;
}
@Override
public
void
onSwiped(RecyclerView.ViewHolder viewHolder,
int
direction) {
//移動刪除回撥,如果不用可以不用理
// mAdapter.onItemDissmiss(viewHolder);
}
@Override
public
void
onSelectedChanged(RecyclerView.ViewHolder viewHolder,
int
actionState) {
super
.onSelectedChanged(viewHolder, actionState);
if
(actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
//當滑動或者拖拽view的時候通過介面返回該ViewHolder
mAdapter.onItemSelect(viewHolder);
}
}
@Override
public
void
clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super
.clearView(recyclerView, viewHolder);
if
(!recyclerView.isComputingLayout()) {
//當需要清除之前在onSelectedChanged或者onChildDraw,onChildDrawOver設定的狀態或者動畫時通過介面返回該ViewHolder
mAdapter.onItemClear(viewHolder);
}
}
}
|
RecycleView.Adapter實現類程式碼
?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 |
/**
* Created by mChenys on 2017/2/15.
*/
public
class
MyAdapter
extends
RecyclerView.Adapter<MyAdapter.MyViewHolder>
implements
ItemTouchHelperAdapter {
...
@Override
public
MyAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent,
int
viewType) {
...
}
@Override
public
void
onBindViewHolder(
final
MyAdapter.MyViewHolder holder,
int
position) {
...
}
@Override
public
int
getItemCount() {
//注意:這裡最少有一個,因為有多了一個新增按鈕
return
null
== mData ?
1
: mData.size() +
1
;
}
@Override
public
void
onItemMove(RecyclerView.ViewHolder source,
RecyclerView.ViewHolder target) {
int
fromPosition = source.getAdapterPosition();
int
toPosition = target.getAdapterPosition();
if
(fromPosition < mData.size() && toPosition < mData.size()) {
//交換資料位置
Collections.swap(mData, fromPosition, toPosition);
//重新整理位置交換
notifyItemMoved(fromPosition, toPosition);
}
//移動過程中移除view的放大效果
onItemClear(source);
}
@Override
public
void
onItemDissmiss(RecyclerView.ViewHolder source) {
int
position = source.getAdapterPosition();
mData.remove(position);
//移除資料
notifyItemRemoved(position);
//重新整理資料移除
}
@Override
public
void
onItemSelect(RecyclerView.ViewHolder viewHolder) {
//當拖拽選中時放大選中的view
viewHolder.itemView.setScaleX(
1
.2f);
viewHolder.itemView.setScaleY(
1
.2f);
}
@Override
public
void
onItemClear(RecyclerView.ViewHolder viewHolder) {
//拖拽結束後恢復view的狀態
viewHolder.itemView.setScaleX(
1
.0f);
viewHolder.itemView.setScaleY(
1
.0f);
}
public
class
MyViewHolder
extends
RecyclerView.ViewHolder {
...
public
MyViewHolder(View itemView) {
super
(itemView);
...
}
}
}
|
MainActivity的使用方式
?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 |
/**
* Created by mChenys on 2017/2/16.
*/
public
class
MainActivity
extends
AppCompatActivity {
...
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
...
mRecyclerView = (RecyclerView) findViewById(R.id.recycleView);
//建立adapter
MyAdapter myAdapter =
new
MyAdapter(
this
, mData);
//設定預設的佈局方式
mRecyclerView.setLayoutManager(
new
LinearLayoutManager(
this
, LinearLayoutManager.VERTICAL,
false
));
//設定adapter
mRecyclerView.setAdapter(myAdapter);
//建立SimpleItemTouchHelperCallback
ItemTouchHelper.Callback callback =
new
SimpleItemTouchHelperCallback(myAdapter);
//用Callback構造ItemtouchHelper
ItemTouchHelper touchHelper =
new
ItemTouchHelper(callback);
//呼叫ItemTouchHelper的attachToRecyclerView方法建立聯絡
touchHelper.attachToRecyclerView(mRecyclerView);
}
@Override
public
boolean
onCreateOptionsMenu(Menu menu) {
...
return
super
.onCreateOptionsMenu(menu);
}
@Override
public
boolean
onOptionsItemSelected(MenuItem item) {
...
return
super
.onOptionsItemSelected(item);
}
}
錯誤解決方法
configurations.all {
resolutionStrategy.eachDependency { DependencyResolveDetails details -> def requested = details.requested if (requested.group == 'com.android.support') { if (!requested.name.startsWith("multidex")) { details.useVersion '25.3.0' } } &nbs |