欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

RecyclerView進階:使用ItemTouchHelper實現(xiàn)拖拽和側(cè)滑刪除效果

 更新時間:2017年02月03日 10:54:11   作者:程序員的自我反思  
現(xiàn)在RecyclerView的應(yīng)用越來越廣泛了,本篇文章主要介紹了RecyclerView進階:使用ItemTouchHelper實現(xiàn)拖拽和側(cè)滑刪除效果,具有一定的參考價值,有興趣的可以了解一下。

前言

現(xiàn)在RecyclerView的應(yīng)用越來越廣泛了,不同的應(yīng)用場景需要其作出不同的改變。有時候我們可能需要實現(xiàn)側(cè)滑刪除的功能,比如知乎首頁的側(cè)滑刪除,又或者長按Item進行拖動與其他Item進行位置的交換,但RecyclerView沒有提供現(xiàn)成的API供我們操作,所幸SDK提供了ItemTouchHelper這樣一個工具類幫助我們快速實現(xiàn)以上功能。不多說別的,我們來介紹一下ItemTouchHelper。

什么是ItemTouchHelper

This is a utility class to add swipe to dismiss and drag & drop support to RecyclerView.It works with a RecyclerView and a Callback class, which configures what type of interactions are enabled and also receives events when user performs these actions.Depending on which functionality you support, you should override onMove(RecyclerView, ViewHolder, ViewHolder) and / or onSwiped(ViewHolder, int).

以上是官方文檔的介紹,ItemTouchHelper是一個工具類,可實現(xiàn)側(cè)滑刪除和拖拽移動,使用這個工具類需要RecyclerView和Callback。同時根據(jù)需要重寫onMove和onSwiped方法。接下來就來講述ItemTouchHelper的使用方法。

ItemTouchHelper基本使用方法

step.1新建一個接口,讓Adapter實現(xiàn)之

從解耦的角度考慮,我們需要一個接口來實現(xiàn)Adapter和ItemTouchHelper之間涉及數(shù)據(jù)的操作,因為ItemTouchHelper在完成觸摸的各種動畫后,就要對Adapter的數(shù)據(jù)進行操作,比如側(cè)滑刪除操作,最后需要調(diào)用Adapter的notifyItemRemove()方法來移除該數(shù)據(jù)。因此我們可以把數(shù)據(jù)操作的部分抽象成一個接口方法,讓ItemTouchHelper.Callback調(diào)用該方法即可。具體如下:

新建ItemTouchHelperAdapter:

public interface ItemTouchHelperAdapter {
  //數(shù)據(jù)交換
  void onItemMove(int fromPosition,int toPosition);
  //數(shù)據(jù)刪除
  void onItemDissmiss(int position);
}

讓我們的Adapter實現(xiàn)該接口:

public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements ItemTouchHelperAdapter {
  //數(shù)據(jù)
  private List<String> mData;
  ...
   @Override
  public void onItemMove(int fromPosition, int toPosition) {
    //交換位置
    Collections.swap(mData,fromPosition,toPosition);
    notifyItemMoved(fromPosition,toPosition);
  }

  @Override
  public void onItemDissmiss(int position) {
    //移除數(shù)據(jù)
    mData.remove(position);
    notifyItemRemoved(position);
  }

}

那么我們在ItemTouchHelper.Callback內(nèi)直接調(diào)用接口的方法即可。

step.2新建類繼承自ItemTouchHelper.Callback

從官方文檔我們知道,使用ItemTouchHelper需要一個Callback,該Callback是ItemTouchHelper.Callback的子類,所以我們需要新建一個類比如SimpleItemTouchHelperCallback繼承自ItemTouchHelper.Callback。我們可以重寫其數(shù)個方法來實現(xiàn)我們的需求。我們先來看看ItemTouchHelper.Callback需要重寫的幾個常用的方法。

1、public int getMovementFlags(RecyclerView, RecyclerView.ViewHolder):該方法用于返回可以滑動的方向,比如說允許從右到左側(cè)滑,允許上下拖動等。我們一般使用makeMovementFlags(int,int)或makeFlag(int, int)來構(gòu)造我們的返回值。

例如:要使RecyclerView的Item可以上下拖動,同時允許從右到左側(cè)滑,但不許允許從左到右的側(cè)滑,我們可以這樣寫:

  @Override
  public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;    //允許上下的拖動
    int swipeFlags = ItemTouchHelper.LEFT;  //只允許從右向左側(cè)滑
    return makeMovementFlags(dragFlags,swipeFlags);
  }

2、public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target)

當(dāng)用戶拖動一個Item進行上下移動從舊的位置到新的位置的時候會調(diào)用該方法,在該方法內(nèi),我們可以調(diào)用Adapter的notifyItemMoved方法來交換兩個ViewHolder的位置,最后返回true,表示被拖動的ViewHolder已經(jīng)移動到了目的位置。所以,如果要實現(xiàn)拖動交換位置,可以重寫該方法(前提是支持上下拖動):

  @Override
  public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
    //onItemMove是接口方法
    mAdapter.onItemMove(viewHolder.getAdapterPosition(),target.getAdapterPosition()); 
    return true;
  }

3、public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction)

當(dāng)用戶左右滑動Item達到刪除條件時,會調(diào)用該方法,一般手指觸摸滑動的距離達到RecyclerView寬度的一半時,再松開手指,此時該Item會繼續(xù)向原先滑動方向滑過去并且調(diào)用onSwiped方法進行刪除,否則會反向滑回原來的位置。在該方法內(nèi)部我們可以這樣寫:

  @Override
  public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
    //onItemDissmiss是接口方法
    mAdapter.onItemDissmiss(viewHolder.getAdapterPosition());
  }

如果在onSwiped方法內(nèi)我們沒有進行任何操作,即不刪除已經(jīng)滑過去的Item,那么就會留下空白的地方,因為實際上該ItemView還占據(jù)著該位置,只是移出了我們的可視范圍內(nèi)罷了。

4、public boolean isLongPressDragEnabled():該方法返回true時,表示支持長按拖動,即長按ItemView后才可以拖動,我們遇到的場景一般也是這樣的。默認(rèn)是返回true。

5、public boolean boolean isItemViewSwipeEnabled():該方法返回true時,表示如果用戶觸摸并左右滑動了View,那么可以執(zhí)行滑動刪除操作,即可以調(diào)用到onSwiped()方法。默認(rèn)是返回true。

6、public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState):從靜止?fàn)顟B(tài)變?yōu)橥献Щ蛘呋瑒拥臅r候會回調(diào)該方法,參數(shù)actionState表示當(dāng)前的狀態(tài)。

7、public void clearView(RecyclerView recyclerView, ViewHolder viewHolder):當(dāng)用戶操作完畢某個item并且其動畫也結(jié)束后會調(diào)用該方法,一般我們在該方法內(nèi)恢復(fù)ItemView的初始狀態(tài),防止由于復(fù)用而產(chǎn)生的顯示錯亂問題。

8、public void onChildDraw(…):我們可以在這個方法內(nèi)實現(xiàn)我們自定義的交互規(guī)則或者自定義的動畫效果。
那么完整的SimpleItemTouchHelperCallback文件是這樣的:

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 swipeFlags = ItemTouchHelper.LEFT;
    return makeMovementFlags(dragFlags,swipeFlags);
  }

  @Override
  public boolean isLongPressDragEnabled() {
    return true;
  }

  @Override
  public boolean isItemViewSwipeEnabled() {
    return true;
  }

  @Override
  public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
    mAdapter.onItemMove(viewHolder.getAdapterPosition(),target.getAdapterPosition());
    return true;
  }

  @Override
  public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
    mAdapter.onItemDissmiss(viewHolder.getAdapterPosition());
  }
}

step.3為RecycleView添加ItemTouchHelper

上面我們修改了Adapter和新建了ItemTouchHelper.Callback的子類,接下來我們要為RecyclerView添加ItemTouchHelper:

  //先實例化Callback
  ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(myAdapter);
  //用Callback構(gòu)造ItemtouchHelper
  ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
  //調(diào)用ItemTouchHelper的attachToRecyclerView方法建立聯(lián)系
  touchHelper.attachToRecyclerView(mRecyclerView);

經(jīng)過以上步驟,我們已經(jīng)實現(xiàn)了Item的拖拽和側(cè)滑刪除功能了,看一下效果:

拖拽和側(cè)滑

自定義側(cè)滑動畫

有時候我們對默認(rèn)的動畫效果可能不滿意,需要自己實現(xiàn)想要的動畫效果,ItemTouchHelper.Callback提供的onChildDraw方法可以讓我們很方便地實現(xiàn)想要的效果。以下帶來一種自定義的實現(xiàn)效果,當(dāng)做拋磚引玉,讓大家熟悉自定義效果的運用。先來看看要實現(xiàn)的效果:

自定義 

該效果是比較常見的,用戶向左滑動Item的時候,一開始提示的是“左滑刪除”,滑動到一定距離后,顯示刪除的圖標(biāo),并且隨著滑動距離的增加該圖標(biāo)不斷變大,達到最大后用戶松開手指,該Item被刪除。

接下來我們來分析一下怎樣實現(xiàn)以上的效果:

首先,要想左滑出現(xiàn)一個刪除的方塊,可以在LinearLayout放一個這樣的“方塊”,讓它與Item水平并排排列,以下是布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  android:layout_height="wrap_content"
  android:layout_width="match_parent"
  android:orientation="horizontal">

  <android.support.v7.widget.CardView
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:background="#ffffff"
    android:layout_marginLeft="4dp"
    android:layout_marginRight="4dp"
    android:layout_marginBottom="4dp"
    app:cardCornerRadius="1dp"
    app:elevation="1dp"
    app:contentPadding="1dp">
    <RelativeLayout
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:background="#ffffff">
      <TextView
        android:id="@+id/item"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="22sp"
        android:padding="4dp"
        android:layout_centerInParent="true"/>

    </RelativeLayout>
  </android.support.v7.widget.CardView>

  <FrameLayout
    android:layout_width="100dp"
    android:layout_height="match_parent"
    android:layout_marginRight="4dp"
    android:layout_marginBottom="4dp"
    android:background="#f33213">

    <ImageView
      android:id="@+id/iv_img"
      android:layout_width="50dp"
      android:layout_height="50dp"
      android:layout_gravity="center"
      android:src="@mipmap/ic_eye_72"
      android:visibility="invisible"/>
    <TextView
      android:id="@+id/tv_text"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="左滑刪除"
      android:textSize="18sp"
      android:textColor="#ffffff"
      android:layout_gravity="center"/>
  </FrameLayout>
</LinearLayout>

布局文件修改后,我們嘗試來滑動一下,發(fā)現(xiàn)后面的刪除方塊并不會出現(xiàn),這是因為默認(rèn)的滑動方式是setTranslationX(int),即是對整個View的滑動,所以無論我們怎樣滑動,都不會出現(xiàn)刪除方塊。因此,我們要改變一個種滑動方式,比如使用scrollTo(int,int),這種是對View的內(nèi)容的滑動,所以隨著左滑,item會向左滑去,而位于右方的方塊自然也就出現(xiàn)了。

接著,我們考慮該“刪除眼睛”的圖標(biāo)是怎樣從小變大的,這個實現(xiàn)也比較簡單,只要根據(jù)滑動的距離對該ImageView的LayoutParams.width進行改變就行了,不過要注意限制大小,否則過大會造成圖片的失真。當(dāng)滑動距離等于RecyclerView寬度的一半時,此時松開手會使Item刪除,那么我們可以在該滑動距離達到該值時時“眼睛”變得最大,此時可以達到良好的交互效果,提示了用戶無需繼續(xù)滑動即可刪除該Item了。

最后我們要考慮的是:在刪除了Item或者沒刪除而滑回原來的位置后,我們要把所做的改變重置一下,否則,會由于RecyclerView的復(fù)用而導(dǎo)致其他位置的ViewHolder與當(dāng)前的ViewHolder所做的改變一樣,即造成顯示的錯誤。我們可以在clearView()方法內(nèi)重置改變,這樣就能解決因復(fù)用而導(dǎo)致的顯示問題了。

最后我們來看看SimpleItemTouchHelperCallback的代碼:

public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback{

  //省略上面的代碼....

  //限制ImageView長度所能增加的最大值
  private double ICON_MAX_SIZE = 50;
  //ImageView的初始長寬
  private int fixedWidth = 150;

  @Override
  public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    super.clearView(recyclerView, viewHolder);
    //重置改變,防止由于復(fù)用而導(dǎo)致的顯示問題
    viewHolder.itemView.setScrollX(0);
    ((MyAdapter.NormalItem)viewHolder).tv.setText("左滑刪除");
    FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) ((MyAdapter.NormalItem) viewHolder).iv.getLayoutParams();
    params.width = 150;
    params.height = 150;
    ((MyAdapter.NormalItem) viewHolder).iv.setLayoutParams(params);
    ((MyAdapter.NormalItem) viewHolder).iv.setVisibility(View.INVISIBLE);
  }

  @Override
  public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
    //僅對側(cè)滑狀態(tài)下的效果做出改變
    if (actionState ==ItemTouchHelper.ACTION_STATE_SWIPE){
      //如果dX小于等于刪除方塊的寬度,那么我們把該方塊滑出來
      if (Math.abs(dX) <= getSlideLimitation(viewHolder)){
        viewHolder.itemView.scrollTo(-(int) dX,0);
      }
      //如果dX還未達到能刪除的距離,此時慢慢增加“眼睛”的大小,增加的最大值為ICON_MAX_SIZE
      else if (Math.abs(dX) <= recyclerView.getWidth() / 2){
        double distance = (recyclerView.getWidth() / 2 -getSlideLimitation(viewHolder));
        double factor = ICON_MAX_SIZE / distance;
        double diff = (Math.abs(dX) - getSlideLimitation(viewHolder)) * factor;
        if (diff >= ICON_MAX_SIZE)
          diff = ICON_MAX_SIZE;
        ((MyAdapter.NormalItem)viewHolder).tv.setText("");  //把文字去掉
        ((MyAdapter.NormalItem) viewHolder).iv.setVisibility(View.VISIBLE); //顯示眼睛
        FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) ((MyAdapter.NormalItem) viewHolder).iv.getLayoutParams();
        params.width = (int) (fixWidth + diff);
        params.height = (int) (fixWidth + diff);
        ((MyAdapter.NormalItem) viewHolder).iv.setLayoutParams(params);
      }
    }else {
      //拖拽狀態(tài)下不做改變,需要調(diào)用父類的方法
      super.onChildDraw(c,recyclerView,viewHolder,dX,dY,actionState,isCurrentlyActive);
    }
  }

  /**
   * 獲取刪除方塊的寬度
   */
  public int getSlideLimitation(RecyclerView.ViewHolder viewHolder){
    ViewGroup viewGroup = (ViewGroup) viewHolder.itemView;
    return viewGroup.getChildAt(1).getLayoutParams().width;
  }
}

好了,到目前為止,自定義效果介紹完畢,讀者可以根據(jù)需求來實現(xiàn)多樣化的效果。

相關(guān)文章

  • Android自定義ViewGroup實現(xiàn)選擇面板

    Android自定義ViewGroup實現(xiàn)選擇面板

    ViewGroup是上面提到的所有的父控件的父類;但ViewGroup是一個抽象類,它里面有一個抽象方法onLayout,這個方法的作用就是擺放它所有的子控件(安排位置),因為是抽象類,不能直接new對象,所以我們在布局文件中不能直接使用 ViewGroup
    2022-07-07
  • Android利用Senser實現(xiàn)不同的傳感器

    Android利用Senser實現(xiàn)不同的傳感器

    這篇文章主要為大家詳細(xì)介紹了Android利用Senser實現(xiàn)不同傳感器的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-02-02
  • Android開發(fā)導(dǎo)入項目報錯Ignoring InnerClasses attribute for an anonymous inner class的解決辦法

    Android開發(fā)導(dǎo)入項目報錯Ignoring InnerClasses attribute for an anonym

    今天小編就為大家分享一篇關(guān)于Android開發(fā)導(dǎo)入項目報錯Ignoring InnerClasses attribute for an anonymous inner class的解決辦法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • Android基于IJKPlayer視頻播放器簡單封裝設(shè)計

    Android基于IJKPlayer視頻播放器簡單封裝設(shè)計

    這篇文章主要介紹了Android基于IJKPlayer視頻播放器簡單封裝設(shè)計,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-06-06
  • RxRetroHttp為多套API請求適配而生

    RxRetroHttp為多套API請求適配而生

    今天小編就為大家分享一篇關(guān)于RxRetroHttp為多套API請求適配而生,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-02-02
  • Android開發(fā)教程之電源管理詳解

    Android開發(fā)教程之電源管理詳解

    這篇文章主要介紹了Android開發(fā)教程之電源管理,較為詳細(xì)的分析了Android電源管理的相關(guān)概念、注意事項與功能實現(xiàn)技巧,需要的朋友可以參考下
    2016-06-06
  • Android仿ios加載loading菊花圖效果

    Android仿ios加載loading菊花圖效果

    這篇文章主要介紹了Android仿ios加載loading菊花圖效果,本文通過實例代碼效果圖展示給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-09-09
  • Android二級緩存加載圖片實現(xiàn)照片墻功能

    Android二級緩存加載圖片實現(xiàn)照片墻功能

    這篇文章主要為大家詳細(xì)介紹了Android二級緩存加載圖片實現(xiàn)照片墻功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • Android獲取周圍WIFI熱點服務(wù)

    Android獲取周圍WIFI熱點服務(wù)

    這篇文章主要為大家詳細(xì)介紹了Android獲取周圍WIFI熱點服務(wù)的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-07-07
  • Android自定義View實現(xiàn)水面上漲效果

    Android自定義View實現(xiàn)水面上漲效果

    這篇文章給大家介紹了利用Android自定義View實現(xiàn)水面上漲效果,對大家日常開發(fā)很有幫助,有需要的朋友們可以參考借鑒。
    2016-09-09

最新評論