如何在android中利用RecyclerView實(shí)現(xiàn)Item的拖拽排序與滑動刪除?很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。
蓮湖網(wǎng)站建設(shè)公司成都創(chuàng)新互聯(lián)公司,蓮湖網(wǎng)站設(shè)計制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為蓮湖近1000家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\成都外貿(mào)網(wǎng)站建設(shè)公司要多少錢,請找那個售后服務(wù)好的蓮湖做網(wǎng)站的公司定做!
需求和技術(shù)分析
實(shí)現(xiàn)方案與技術(shù)
利用ItemTouchHelper綁定RecyclerView、ItemTouchHelper.Callback來實(shí)現(xiàn)UI更新,并且實(shí)現(xiàn)動態(tài)控制是否開啟拖拽功能和滑動刪除功能。
實(shí)現(xiàn)步驟
幾個主要的布局
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
這個沒啥好說的了吧,就是一個RecyclerView啦。
接下來是RecyclerView的Item的布局item.xml:
<?xml version="1.0" encoding="utf-8"?>
這個也不用解釋了,到時候下載看源碼,就是普通item,展示數(shù)據(jù)而已。
實(shí)現(xiàn)自己的DefaultItemTouchHelper:繼承ItemTouchHelper
public class DefaultItemTouchHelper extends ItemTouchHelper { public DefaultItemTouchHelper(ItemTouchHelp.Callback callback) { super(callback); } }
好嘛,這個太簡單了,基本上一行代碼都不用寫。但是這里需要一個ItemTouchHelp.Callback啊,所以我們還是要實(shí)現(xiàn)一個ItemTouchHelp.Callback,客觀且看下文分解。
實(shí)現(xiàn)自己的ItemTouchHelper.Callback:繼承ItemTouchHelper.Callback
這里是全文最重要的部分啦,要認(rèn)真點(diǎn)看噢,先上代碼,后解釋,其他看注釋和視頻。
public class DefaultItemTouchHelpCallback extends ItemTouchHelper.Callback { /** * Item操作的回調(diào) */ private OnItemTouchCallbackListener onItemTouchCallbackListener; /** * 是否可以拖拽 */ private boolean isCanDrag = false; /** * 是否可以被滑動 */ private boolean isCanSwipe = false; public DefaultItemTouchHelpCallback(OnItemTouchCallbackListener onItemTouchCallbackListener) { this.onItemTouchCallbackListener = onItemTouchCallbackListener; } /** * 設(shè)置Item操作的回調(diào),去更新UI和數(shù)據(jù)源 * * @param onItemTouchCallbackListener */ public void setOnItemTouchCallbackListener(OnItemTouchCallbackListener onItemTouchCallbackListener) { this.onItemTouchCallbackListener = onItemTouchCallbackListener; } /** * 設(shè)置是否可以被拖拽 * * @param canDrag 是true,否false */ public void setDragEnable(boolean canDrag) { isCanDrag = canDrag; } /** * 設(shè)置是否可以被滑動 * * @param canSwipe 是true,否false */ public void setSwipeEnable(boolean canSwipe) { isCanSwipe = canSwipe; } /** * 當(dāng)Item被長按的時候是否可以被拖拽 * * @return */ @Override public boolean isLongPressDragEnabled() { return isCanDrag; } /** * Item是否可以被滑動(H:左右滑動,V:上下滑動) * * @return */ @Override public boolean isItemViewSwipeEnabled() { return isCanSwipe; } /** * 當(dāng)用戶拖拽或者滑動Item的時候需要我們告訴系統(tǒ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)于這個功能被關(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被拖拽的時候被回調(diào) * * @param recyclerView recyclerView * @param srcViewHolder 拖拽的ViewHolder * @param targetViewHolder 目的地的viewHolder * @return */ @Override public boolean onMove(RecyclerView recyclerView, ViewHolder srcViewHolder, ViewHolder targetViewHolder) { if (onItemTouchCallbackListener != null) { return onItemTouchCallbackListener.onMove(srcViewHolder.getAdapterPosition(), targetViewHolder.getAdapterPosition()); } return false; } @Override public void onSwiped(ViewHolder viewHolder, int direction) { if (onItemTouchCallbackListener != null) { onItemTouchCallbackListener.onSwiped(viewHolder.getAdapterPosition()); } } public interface OnItemTouchCallbackListener { /** * 當(dāng)某個Item被滑動刪除的時候 * * @param adapterPosition item的position */ void onSwiped(int adapterPosition); /** * 當(dāng)兩個Item位置互換的時候被回調(diào) * * @param srcPosition 拖拽的item的position * @param targetPosition 目的地的Item的position * @return 開發(fā)者處理了操作應(yīng)該返回true,開發(fā)者沒有處理就返回false */ boolean onMove(int srcPosition, int targetPosition); } }
好,其實(shí)上面最重要的就是五個方法:
/** * 是否可以長按拖拽排序。 */ @Override public boolean isLongPressDragEnabled() {} /** * Item是否可以被滑動(H:左右滑動,V:上下滑動) */ @Override public boolean isItemViewSwipeEnabled() {} /** * 當(dāng)用戶拖拽或者滑動Item的時候需要我們告訴系統(tǒng)滑動或者拖拽的方向 */ @Override public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {} /** * 當(dāng)Item被拖拽的時候被回調(diào) */ @Override public boolean onMove(RecyclerView r, ViewHolder rholer, ViewHolder tholder) {} /** * 當(dāng)View被滑動刪除的時候 */ @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {}
isItemViewSwipeEnabled()返回值是否可以拖拽排序,true可以,false不可以,isItemViewSwipeEnabled()是否可以滑動刪除,true可以,false不可以;這兩個方法都是配置是否可以操作的。我們上面的代碼中返回了一個成員變量值,并且這個值通過外部可以修改,所以提供了外部控制的方法。
onMove()當(dāng)Item被拖拽排序移動到另一個Item的位置的時候被回調(diào),onSwiped()當(dāng)Item被滑動刪除到不見;這兩個方法是當(dāng)用戶操作了,來回調(diào)我們,我們就該去更新UI了。這里我們提供了一個Listener去通知外部,并且返回出去了必要的值,來降低代碼耦合度。
getMovementFlags()說明一:是當(dāng)用戶拖拽或者滑動Item的時候需要我們告訴系統(tǒng)滑動或者拖拽的方向,那我們又知道支持拖拽和滑動刪除的無非就是LinearLayoutManager和GridLayoutManager了,相當(dāng)于我們老早的時候用的ListView和GridView了。所以我們根據(jù)布局管理器的不同做了響應(yīng)的區(qū)分。
getMovementFlags()說明二:其他都好理解,就是這里的return makeMovementFlags(dragFlag, swipeFlag);這句話是最終的返回值,也就是它決定了我們的拖拽或者滑動的方法。第一個參數(shù)是拖拽flag,第二個是滑動的flag。
重新定義DefaultItemTouchHelper
我們記得上面定義了一個DefaultItemTouchHelper,它的構(gòu)造中需要傳一個ItemTouchHelper.Callback,既然我們實(shí)現(xiàn)禮了,我們再把DefaultItemTouchHelper做個封裝,使使用者更傻瓜式的調(diào)用。
public class DefaultItemTouchHelper extends YolandaItemTouchHelper { private DefaultItemTouchHelpCallback itemTouchHelpCallback; public DefaultItemTouchHelper(DefaultItemTouchHelpCallback.OnItemTouchCallbackListener onItemTouchCallbackListener) { super(new DefaultItemTouchHelpCallback(onItemTouchCallbackListener)); itemTouchHelpCallback = (DefaultItemTouchHelpCallback) getCallback(); } /** * 設(shè)置是否可以被拖拽 * * @param canDrag 是true,否false */ public void setDragEnable(boolean canDrag) { itemTouchHelpCallback.setDragEnable(canDrag); } /** * 設(shè)置是否可以被滑動 * * @param canSwipe 是true,否false */ public void setSwipeEnable(boolean canSwipe) { itemTouchHelpCallback.setSwipeEnable(canSwipe); } }
現(xiàn)在我們看到已經(jīng)不需要傳ItemTouchHelper.Callback給ItemTouchHelper了,只需要傳我們在DefaultItemTouchHelpCallback中定義好的OnItemTouchCallbackListener就好了,而且提供了設(shè)置是否可以滑動和是否可以拖拽的方法,而OnItemTouchCallbackListener只是通知外部滑動了、刪除了,你去更新UI吧。
這里可以有的同學(xué)會有疑問,上面原來不是繼承ItemTouchHelper嗎?這里咋就變成了YolandaItemTouchHelper了呢?因?yàn)槲覀兛吹竭@里多了一句itemTouchHelpCallback = getCallback();,這個getCallback();這個方法是沒有的,是我們在YolandaItemTouchHelper中自定義的,因?yàn)槲覀兿朐贒efaultItemTouchHelper中提供外部設(shè)置是否可以拖拽和滑動刪除的方法,就得拿到這個Callback,所以我看了下源碼,我們在ItemTouchHelper構(gòu)造中把Callback穿進(jìn)去,它保存的時候一個package級別的成員變量,所以我在Android.support.v7.widget.helper包下新建了一個YolandaItemTouchHelper類:
public class YolandaItemTouchHelper extends ItemTouchHelper { public YolandaItemTouchHelper(Callback callback) { super(callback); } public Callback getCallback() { return mCallback; } }
如何投入使用
好扯淡也扯完了,封裝也封裝完了,那么接下來就來在Activity中使用下咯:
recyclerView綁定ItemTouchHelper
沒啥好說的用itemTouchHelper.attachToRecyclerView(recyclerView)綁定recyclerView和ItemTouchHelper,并且只是允許拖拽和滑動刪除Item:
DefaultItemTouchHelper itemTouchHelper = new DefaultItemTouchHelper(onItemTouchCallbackListener); itemTouchHelper.attachToRecyclerView(recyclerView); itemTouchHelper.setDragEnable(true); itemTouchHelper.setSwipeEnable(true);
看到上面還缺少一個onItemTouchCallbackListener吧,這個也比較重要。
使用Callback自定義的OnItemTouchCallbackListener刷新UI
我們在自定義Callback的時候不是在onMove()和onSwiped()方法中回調(diào)OnItemTouchCallbackListener去更新UI嗎?這里就是OnItemTouchCallbackListener如何更新UI的操作了,完成這個操作,那么我們的目的就達(dá)到了:
private DefaultItemTouchHelpCallback.OnItemTouchCallbackListener onItemTouchCallbackListener = new DefaultItemTouchHelpCallback.OnItemTouchCallbackListener() { @Override public void onSwiped(int adapterPosition) { // 滑動刪除的時候,從數(shù)據(jù)源移除,并刷新這個Item。 if (userInfoList != null) { userInfoList.remove(adapterPosition); mainAdapter.notifyItemRemoved(adapterPosition); } } @Override public boolean onMove(int srcPosition, int targetPosition) { if (userInfoList != null) { // 更換數(shù)據(jù)源中的數(shù)據(jù)Item的位置 Collections.swap(userInfoList, srcPosition, targetPosition); // 更新UI中的Item的位置,主要是給用戶看到交互效果 mainAdapter.notifyItemMoved(srcPosition, targetPosition); return true; } return false; } };
看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進(jìn)一步的了解或閱讀更多相關(guān)文章,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝您對創(chuàng)新互聯(lián)的支持。