效果演示
<img src="http://upload-images.jianshu.io/upload_images/2918620-eb4210464ce2c4b4.gif?imageMogr2/auto-orient/strip"/>
需求和技術(shù)分析
- RecyclerView Item拖拽排序:長按RecyclerView的Item或者觸摸Item的某個(gè)按鈕饵蒂。
- RecyclerView Item滑動(dòng)刪除:RecyclerView Item滑動(dòng)刪除:RecyclerView的Item滑動(dòng)刪除墓怀。
實(shí)現(xiàn)方案與技術(shù)
利用ItemTouchHelper綁定RecyclerView细卧、ItemTouchHelper.Callback來實(shí)現(xiàn)UI更新,并且實(shí)現(xiàn)動(dòng)態(tài)控制是否開啟拖拽功能和滑動(dòng)刪除功能丐一。
實(shí)現(xiàn)步驟
- 繼承抽象類ItemTouchHelper铃岔,并在構(gòu)造方法傳入實(shí)現(xiàn)的ItemTouchHelper.Callback江咳。
- recyclerView綁定ItemTouchHelper:itemTouchHelper.attachToRecyclerView(recyclerView)。
- 自定義ItemTouchHelper.Callback的實(shí)現(xiàn)接口OnItemTouchCallbackListener钥庇,由外部更新RecyclerView的Item牍鞠。
幾個(gè)主要的布局
實(shí)現(xiàn)ItemTouchHelperCallback并繼承自ItemTouchHelper.Callback
public class ItemTouchHelperCallback extends ItemTouchHelper.Callback {
private final ItemTouchHelperAdapter mAdapter;
/**
* 是否可以拖拽
*/
private boolean isCanDrag = false;
/**
* 是否可以被滑動(dòng)
*/
private boolean isCanSwipe = false;
public ItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {
mAdapter = adapter;
}
public ItemTouchHelperCallback(ItemTouchHelperAdapter adapter,boolean canDrag,boolean canSwipe) {
mAdapter = adapter;
this.isCanDrag = canDrag;
this.isCanSwipe = canSwipe;
}
/**
* 設(shè)置是否可以被拖拽
*
* @param canDrag 是true,否false
*/
public void setDragEnable(boolean canDrag) {
isCanDrag = canDrag;
}
/**
* 設(shè)置是否可以被滑動(dòng)
*
* @param canSwipe 是true评姨,否false
*/
public void setSwipeEnable(boolean canSwipe) {
isCanSwipe = canSwipe;
}
/**
* 當(dāng)Item被長按的時(shí)候是否可以被拖拽
* @return
*/
@Override
public boolean isLongPressDragEnabled() {
return isCanDrag;
}
/**
* Item是否可以被滑動(dòng)(H:左右滑動(dòng)难述,V:上下滑動(dòng))
* @return
*/
@Override
public boolean isItemViewSwipeEnabled() {
return isCanSwipe;
}
/**
* 當(dāng)用戶拖拽或者滑動(dòng)Item的時(shí)候需要我們告訴系統(tǒng)滑動(dòng)或者拖拽的方向
* @param recyclerView
* @param viewHolder
* @return
*/
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {// GridLayoutManager
// flag如果值是0,相當(dāng)于這個(gè)功能被關(guān)閉
int dragFlag = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT | ItemTouchHelper.UP | ItemTouchHelper.DOWN;
int swipeFlag = 0;
// create make
return makeMovementFlags(dragFlag, swipeFlag);
} else if (layoutManager instanceof LinearLayoutManager) {// linearLayoutManager
LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager;
int orientation = linearLayoutManager.getOrientation();
int dragFlag = 0;
int swipeFlag = 0;
// 為了方便理解吐句,相當(dāng)于分為橫著的ListView和豎著的ListView
if (orientation == LinearLayoutManager.HORIZONTAL) {// 如果是橫向的布局
swipeFlag = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
dragFlag = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
} else if (orientation == LinearLayoutManager.VERTICAL) {// 如果是豎向的布局胁后,相當(dāng)于ListView
dragFlag = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
swipeFlag = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
}
return makeMovementFlags(dragFlag, swipeFlag);
}
return 0;
}
/**
* 當(dāng)Item被拖拽的時(shí)候被回調(diào)
* @param recyclerView
* @param viewHolder
* @param target
* @return
*/
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
/**
* 回調(diào)
*/
mAdapter.onMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int i) {
/**
* 回調(diào)
*/
mAdapter.onSwipe(viewHolder.getAdapterPosition());
}
}
上面主要就五個(gè)方法比較重要
/**
* 是否可以長按拖拽排序。
*/
@Override
public boolean isLongPressDragEnabled() {}
/**
* Item是否可以被滑動(dòng)(H:左右滑動(dòng)嗦枢,V:上下滑動(dòng))
*/
@Override
public boolean isItemViewSwipeEnabled() {}
/**
* 當(dāng)用戶拖拽或者滑動(dòng)Item的時(shí)候需要我們告訴系統(tǒng)滑動(dòng)或者拖拽的方向
*/
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {}
/**
* 當(dāng)Item被拖拽的時(shí)候被回調(diào)
*/
@Override
public boolean onMove(RecyclerView r, ViewHolder rholer, ViewHolder tholder) {}
/**
* 當(dāng)View被滑動(dòng)刪除的時(shí)候
*/
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {}
isItemViewSwipeEnabled()
返回值是否可以拖拽排序攀芯,true可以,false不可以文虏,isItemViewSwipeEnabled()
是否可以滑動(dòng)刪除侣诺,true可以,false不可以择葡;這兩個(gè)方法都是配置是否可以操作的紧武。我們上面的代碼中返回了一個(gè)成員變量值,并且這個(gè)值通過外部可以修改敏储,所以提供了外部控制的方法阻星。
onMove()
當(dāng)Item被拖拽排序移動(dòng)到另一個(gè)Item的位置的時(shí)候被回調(diào),onSwiped()
當(dāng)Item被滑動(dòng)刪除到不見;這兩個(gè)方法是當(dāng)用戶操作了妥箕,來回調(diào)我們滥酥,我們就該去更新UI了。這里我們提供了一個(gè)Listener去通知外部畦幢,并且返回出去了必要的值坎吻,來降低代碼耦合度。
getMovementFlags()
說明一:是當(dāng)用戶拖拽或者滑動(dòng)Item的時(shí)候需要我們告訴系統(tǒng)滑動(dòng)或者拖拽的方向宇葱,那我們又知道支持拖拽和滑動(dòng)刪除的無非就是LinearLayoutManager
和GridLayoutManager
了瘦真,相當(dāng)于我們老早的時(shí)候用的ListView
和GridView
了。所以我們根據(jù)布局管理器的不同做了響應(yīng)的區(qū)分黍瞧。
getMovementFlags()
說明二:其他都好理解诸尽,就是這里的return makeMovementFlags(dragFlag, swipeFlag)
;這句話是最終的返回值,也就是它決定了我們的拖拽或者滑動(dòng)的方法印颤。第一個(gè)參數(shù)是拖拽flag您机,第二個(gè)是滑動(dòng)的flag。
實(shí)現(xiàn)ItemTouchHelperAdapter接口
用于監(jiān)聽長按拖拽或滑動(dòng)刪除時(shí)的事件
public interface ItemTouchHelperAdapter {
/**
* @param fromPosition 起始位置
* @param toPosition 移動(dòng)的位置
*/
void onMove(int fromPosition, int toPosition);
void onSwipe(int position);
}
定義RecyclerViewAdapter并實(shí)現(xiàn)ItemTouchHelperAdapter 接口
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> implements ItemTouchHelperAdapter{
private List<String> mDataList = new ArrayList<>();
/**
* 當(dāng)加載更多的時(shí)候可以使用
*
* @param dataList
*/
public void addData(List<String> dataList) {
if (dataList != null) {
mDataList.addAll(dataList);
}
notifyDataSetChanged();
}
/**
* 更新Adapter
*
* @param dataList
*/
public void replaceData(List<String> dataList) {
if (dataList != null) {
mDataList.clear();
addData(dataList);
}
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_main, parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
String data = mDataList.get(position);
holder.tv.setText(data);
}
@Override
public int getItemCount() {
return mDataList.size();
}
@Override
public void onMove(int fromPosition, int toPosition) {
/**
* 在這里進(jìn)行給原數(shù)組數(shù)據(jù)的移動(dòng)
*/
Collections.swap(mDataList, fromPosition, toPosition);
/**
* 通知數(shù)據(jù)移動(dòng)
*/
notifyItemMoved(fromPosition, toPosition);
}
@Override
public void onSwipe(int position) {
/**
* 原數(shù)據(jù)移除數(shù)據(jù)
*/
mDataList.remove(position);
/**
* 通知移除
*/
notifyItemRemoved(position);
}
class ViewHolder extends RecyclerView.ViewHolder{
private TextView tv;
private ImageView iv;
public ViewHolder(View itemView) {
super(itemView);
tv = (TextView) itemView.findViewById(R.id.text);
iv = (ImageView) itemView.findViewById(R.id.handle);
}
}
}
最后讓RecyclerView綁定ItemTouchHelper
public class MainActivity extends AppCompatActivity {
private RecyclerViewAdapter mAdapter;
private RecyclerView mRecyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView) findViewById(R.id.rv);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false));
// mRecyclerView.setLayoutManager(new GridLayoutManager(this,3));
mAdapter = new RecyclerViewAdapter();
mRecyclerView.setAdapter(mAdapter);
initData();
}
private void initData() {
List<String> list = new ArrayList<>();
for(int i=0;i<100;i++){
list.add("第"+i+"個(gè)");
}
mAdapter.addData(list);
ItemTouchHelperCallback helperCallback = new ItemTouchHelperCallback(mAdapter);
helperCallback.setSwipeEnable(true);
helperCallback.setDragEnable(true);
ItemTouchHelper helper = new ItemTouchHelper(helperCallback);
helper.attachToRecyclerView(mRecyclerView);
}
}
到此結(jié)束
<a >源碼下載</a>
申明:以上有些解釋是借鑒網(wǎng)上的