国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

android RecyclerView實現條目Item拖拽排序與滑動刪除

2019-10-23 19:44:08
字體:
來源:轉載
供稿:網友

效果演示

recyclerview刪除條目,recyclerview拖拽排序,android,RecyclerView

需求和技術分析

  • RecyclerView Item拖拽排序::長按RecyclerView的Item或者觸摸Item的某個按鈕。
  • RecyclerView Item滑動刪除:RecyclerView Item滑動刪除:RecyclerView的Item滑動刪除。

實現方案與技術

利用ItemTouchHelper綁定RecyclerView、ItemTouchHelper.Callback來實現UI更新,并且實現動態控制是否開啟拖拽功能和滑動刪除功能。

實現步驟

  • 繼承抽象類ItemTouchHelper,并在構造方法傳入實現的ItemTouchHelper.Callback。
  • recyclerView綁定ItemTouchHelper:itemTouchHelper.attachToRecyclerView(recyclerView)。
  • 自定義ItemTouchHelper.Callback的實現接口OnItemTouchCallbackListener,由外部更新RecyclerView的Item。

幾個主要的布局

activity_main.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  android:layout_width="match_parent"  android:layout_height="match_parent"  android:orientation="vertical">  <android.support.v7.widget.RecyclerView    android:id="@+id/rv_main"    android:layout_width="match_parent"    android:layout_height="wrap_content" /></LinearLayout>

這個沒啥好說的了吧,就是一個RecyclerView啦。

接下來是RecyclerView的Item的布局item.xml:

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  android:layout_width="match_parent"  android:layout_height="?android:listPreferredItemHeight"  android:background="?selectableItemBackground">  <ImageView    android:id="@+id/iv_touch"    style="@style/ItemStyle"    android:layout_height="match_parent"    android:layout_alignParentEnd="true"    android:layout_alignParentRight="true"    android:src="@android:drawable/alert_dark_frame" />  <CheckBox    android:id="@+id/cb_item_check"    style="@style/ItemStyle"    android:layout_alignParentLeft="true"    android:layout_alignParentStart="true" />  <TextView    android:id="@+id/tv_name"    style="@style/ItemStyle"    android:layout_toEndOf="@id/cb_item_check"    android:layout_toRightOf="@id/cb_item_check" />  <TextView    android:id="@+id/tv_sex"    style="@style/ItemStyle"    android:layout_marginLeft="@dimen/dp_10"    android:layout_marginStart="@dimen/dp_10"    android:layout_toEndOf="@id/tv_name"    android:layout_toRightOf="@id/tv_name" /></RelativeLayout>

這個也不用解釋了,到時候下載看源碼,就是普通item,展示數據而已。

實現自己的DefaultItemTouchHelper:繼承ItemTouchHelper

public class DefaultItemTouchHelper extends ItemTouchHelper {  public DefaultItemTouchHelper(ItemTouchHelp.Callback callback) {    super(callback);  }}

好嘛,這個太簡單了,基本上一行代碼都不用寫。但是這里需要一個ItemTouchHelp.Callback啊,所以我們還是要實現一個ItemTouchHelp.Callback,客觀且看下文分解。

實現自己的ItemTouchHelper.Callback:繼承ItemTouchHelper.Callback

這里是全文最重要的部分啦,要認真點看噢,先上代碼,后解釋,其他看注釋和視頻。

public class DefaultItemTouchHelpCallback extends ItemTouchHelper.Callback {  /**   * Item操作的回調   */  private OnItemTouchCallbackListener onItemTouchCallbackListener;  /**   * 是否可以拖拽   */  private boolean isCanDrag = false;  /**   * 是否可以被滑動   */  private boolean isCanSwipe = false;  public DefaultItemTouchHelpCallback(OnItemTouchCallbackListener onItemTouchCallbackListener) {    this.onItemTouchCallbackListener = onItemTouchCallbackListener;  }  /**   * 設置Item操作的回調,去更新UI和數據源   *   * @param onItemTouchCallbackListener   */  public void setOnItemTouchCallbackListener(OnItemTouchCallbackListener onItemTouchCallbackListener) {    this.onItemTouchCallbackListener = onItemTouchCallbackListener;  }  /**   * 設置是否可以被拖拽   *   * @param canDrag 是true,否false   */  public void setDragEnable(boolean canDrag) {    isCanDrag = canDrag;  }  /**   * 設置是否可以被滑動   *   * @param canSwipe 是true,否false   */  public void setSwipeEnable(boolean canSwipe) {    isCanSwipe = canSwipe;  }  /**   * 當Item被長按的時候是否可以被拖拽   *   * @return   */  @Override  public boolean isLongPressDragEnabled() {    return isCanDrag;  }  /**   * Item是否可以被滑動(H:左右滑動,V:上下滑動)   *   * @return   */  @Override  public boolean isItemViewSwipeEnabled() {    return isCanSwipe;  }  /**   * 當用戶拖拽或者滑動Item的時候需要我們告訴系統滑動或者拖拽的方向   *   * @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,相當于這個功能被關閉      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;      // 為了方便理解,相當于分為橫著的ListView和豎著的ListView      if (orientation == LinearLayoutManager.HORIZONTAL) {// 如果是橫向的布局        swipeFlag = ItemTouchHelper.UP | ItemTouchHelper.DOWN;        dragFlag = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;      } else if (orientation == LinearLayoutManager.VERTICAL) {// 如果是豎向的布局,相當于ListView        dragFlag = ItemTouchHelper.UP | ItemTouchHelper.DOWN;        swipeFlag = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;      }      return makeMovementFlags(dragFlag, swipeFlag);    }    return 0;  }  /**   * 當Item被拖拽的時候被回調   *   * @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 {    /**     * 當某個Item被滑動刪除的時候     *     * @param adapterPosition item的position     */    void onSwiped(int adapterPosition);    /**     * 當兩個Item位置互換的時候被回調     *     * @param srcPosition  拖拽的item的position     * @param targetPosition 目的地的Item的position     * @return 開發者處理了操作應該返回true,開發者沒有處理就返回false     */    boolean onMove(int srcPosition, int targetPosition);  }}

好,其實上面最重要的就是五個方法:

/** * 是否可以長按拖拽排序。 */@Overridepublic boolean isLongPressDragEnabled() {}/** * Item是否可以被滑動(H:左右滑動,V:上下滑動) */@Overridepublic boolean isItemViewSwipeEnabled() {}/** * 當用戶拖拽或者滑動Item的時候需要我們告訴系統滑動或者拖拽的方向 */@Overridepublic int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {}/** * 當Item被拖拽的時候被回調 */@Overridepublic boolean onMove(RecyclerView r, ViewHolder rholer, ViewHolder tholder) {}/** * 當View被滑動刪除的時候 */@Overridepublic void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {}

isItemViewSwipeEnabled()返回值是否可以拖拽排序,true可以,false不可以,isItemViewSwipeEnabled()是否可以滑動刪除,true可以,false不可以;這兩個方法都是配置是否可以操作的。我們上面的代碼中返回了一個成員變量值,并且這個值通過外部可以修改,所以提供了外部控制的方法。

onMove()當Item被拖拽排序移動到另一個Item的位置的時候被回調,onSwiped()當Item被滑動刪除到不見;這兩個方法是當用戶操作了,來回調我們,我們就該去更新UI了。這里我們提供了一個Listener去通知外部,并且返回出去了必要的值,來降低代碼耦合度。

getMovementFlags()說明一:是當用戶拖拽或者滑動Item的時候需要我們告訴系統滑動或者拖拽的方向,那我們又知道支持拖拽和滑動刪除的無非就是LinearLayoutManager和GridLayoutManager了,相當于我們老早的時候用的ListView和GridView了。所以我們根據布局管理器的不同做了響應的區分。

getMovementFlags()說明二:其他都好理解,就是這里的return makeMovementFlags(dragFlag, swipeFlag);這句話是最終的返回值,也就是它決定了我們的拖拽或者滑動的方法。第一個參數是拖拽flag,第二個是滑動的flag。

重新定義DefaultItemTouchHelper

我們記得上面定義了一個DefaultItemTouchHelper,它的構造中需要傳一個ItemTouchHelper.Callback,既然我們實現禮了,我們再把DefaultItemTouchHelper做個封裝,使使用者更傻瓜式的調用。

public class DefaultItemTouchHelper extends YolandaItemTouchHelper {  private DefaultItemTouchHelpCallback itemTouchHelpCallback;  public DefaultItemTouchHelper(DefaultItemTouchHelpCallback.OnItemTouchCallbackListener onItemTouchCallbackListener) {    super(new DefaultItemTouchHelpCallback(onItemTouchCallbackListener));    itemTouchHelpCallback = (DefaultItemTouchHelpCallback) getCallback();  }  /**   * 設置是否可以被拖拽   *   * @param canDrag 是true,否false   */  public void setDragEnable(boolean canDrag) {    itemTouchHelpCallback.setDragEnable(canDrag);  }  /**   * 設置是否可以被滑動   *   * @param canSwipe 是true,否false   */  public void setSwipeEnable(boolean canSwipe) {    itemTouchHelpCallback.setSwipeEnable(canSwipe);  }}

現在我們看到已經不需要傳ItemTouchHelper.Callback給ItemTouchHelper了,只需要傳我們在DefaultItemTouchHelpCallback中定義好的OnItemTouchCallbackListener就好了,而且提供了設置是否可以滑動和是否可以拖拽的方法,而OnItemTouchCallbackListener只是通知外部滑動了、刪除了,你去更新UI吧。

這里可以有的同學會有疑問,上面原來不是繼承ItemTouchHelper嗎?這里咋就變成了YolandaItemTouchHelper了呢?因為我們看到這里多了一句itemTouchHelpCallback = getCallback();,這個getCallback();這個方法是沒有的,是我們在YolandaItemTouchHelper中自定義的,因為我們想在DefaultItemTouchHelper中提供外部設置是否可以拖拽和滑動刪除的方法,就得拿到這個Callback,所以我看了下源碼,我們在ItemTouchHelper構造中把Callback穿進去,它保存的時候一個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()方法中回調OnItemTouchCallbackListener去更新UI嗎?這里就是OnItemTouchCallbackListener如何更新UI的操作了,完成這個操作,那么我們的目的就達到了:

private DefaultItemTouchHelpCallback.OnItemTouchCallbackListener onItemTouchCallbackListener = new DefaultItemTouchHelpCallback.OnItemTouchCallbackListener() {  @Override  public void onSwiped(int adapterPosition) {    // 滑動刪除的時候,從數據源移除,并刷新這個Item。    if (userInfoList != null) {      userInfoList.remove(adapterPosition);      mainAdapter.notifyItemRemoved(adapterPosition);    }  }  @Override  public boolean onMove(int srcPosition, int targetPosition) {    if (userInfoList != null) {      // 更換數據源中的數據Item的位置      Collections.swap(userInfoList, srcPosition, targetPosition);      // 更新UI中的Item的位置,主要是給用戶看到交互效果      mainAdapter.notifyItemMoved(srcPosition, targetPosition);      return true;    }    return false;  }};

到這里就結束了,不信你去試試,源碼傳送門

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 容城县| 紫阳县| 苗栗市| 尼玛县| 子长县| 砀山县| 萍乡市| 宜州市| 翁牛特旗| 手机| 怀远县| 凌云县| 元氏县| 德保县| 阿鲁科尔沁旗| 唐海县| 阜阳市| 景泰县| 青铜峡市| 九台市| 泽州县| 荣昌县| 个旧市| 西贡区| 廉江市| 邛崃市| 边坝县| 芮城县| 门头沟区| 左云县| 白沙| 资兴市| 宜昌市| 武冈市| 开化县| 临夏市| 灌南县| 静安区| 平乐县| 会宁县| 新泰市|