1. 程式人生 > >RecyclerView的中級進階 側滑刪除和拖拽排序

RecyclerView的中級進階 側滑刪除和拖拽排序

RecyclerView相信大家都已經瞭解,以前我們使用的listView,gradView漸漸的使用的人越來越少.可以說RecyclerView肯定會取代listView,gradView.今天我們來講講recyclerview的側滑刪除和拖拽排序.不瞭解RecyclerView的請自行去百度

在很多時候我們需要使用這樣的功能,如果自己用程式碼去實現拖動排序與滑動刪除會比較麻煩還好谷歌為我們提供了一個工具類ItemTouchHelper

官方的解釋是它是一個可以給RecyclerView提供新增拖動排序與滑動刪除等等操作的工具類。

簡單實現

第一步 首先我們建立一個介面ItemTouchHelperAdapter

public interface ItemTouchHelperAdapter {

    //資料交換
    void onItemMove(int fromPosition, int toPosition);

    //資料刪除
    void onItemDissmiss(int position);

}
第二步建立一個類SimpleItemTouchHelperCallback繼承自ItemTouchHelper.Callback

public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
private ItemTouchHelperAdapter mAdapter;

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


public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {
    mAdapter = adapter;
}

/**
 * 該方法用於返回可以滑動的方向,比如說允許從右到左側滑,允許上下拖動等。我們一般使用makeMovementFlags(int,int)或makeFlag(int, int)來構造我們的返回值。
 * 例如:要使RecyclerView的Item可以上下拖動,同時允許從右到左側滑,但不許允許從左到右的側滑,我們可以這樣寫:
 *
 * @param recyclerView
 * @param viewHolder
 * @return
 */
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; //允許上下的拖動
    int swipeFlags = ItemTouchHelper.LEFT; //只允許從右向左側滑
    return makeMovementFlags(dragFlags, swipeFlags);
    //  return 0;
}

/**
 * 當用戶拖動一個Item進行上下移動從舊的位置到新的位置的時候會呼叫該方法,在該方法內,我們可以呼叫Adapter的notifyItemMoved方法來交換兩個ViewHolder的位置,
 * 最後返回true,表示被拖動的ViewHolder已經移動到了目的位置。所以,如果要實現拖動交換位置,可以重寫該方法(前提是支援上下拖動):
 *
 * @param recyclerView
 * @param viewHolder
 * @param target
 * @return
 */
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
    //onItemMove是介面方法
    mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
    return true;
    //  return false;
}

/**
 * 當用戶左右滑動Item達到刪除條件時,會呼叫該方法,一般手指觸控滑動的距離達到RecyclerView寬度的一半時,再鬆開手指,
 * 此時該Item會繼續向原先滑動方向滑過去並且呼叫onSwiped方法進行刪除,否則會反向滑回原來的位置。在該方法內部我們可以這樣寫:
 *
 * @param viewHolder
 * @param direction
 */
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
    //onItemDissmiss是介面方法
    mAdapter.onItemDissmiss(viewHolder.getAdapterPosition());
}

/**
 * 該方法返回true時,表示支援長按拖動,即長按ItemView後才可以拖動,我們遇到的場景一般也是這樣的。預設是返回true。
 *
 * @return
 */
@Override
public boolean isLongPressDragEnabled() {
    return true;
}

/**
 * 該方法返回true時,表示如果使用者觸控並左右滑動了View,那麼可以執行滑動刪除操作,即可以呼叫到onSwiped()方法。預設是返回true。
 *
 * @return
 */
@Override
public boolean isItemViewSwipeEnabled() {
    return true;
}

/**
 * 從靜止狀態變為拖拽或者滑動的時候會回撥該方法,引數actionState表示當前的狀態。
 *
 * @param viewHolder
 * @param actionState
 */
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
    super.onSelectedChanged(viewHolder, actionState);
}

/**
 * 當用戶操作完畢某個item並且其動畫也結束後會呼叫該方法,一般我們在該方法內恢復ItemView的初始狀態,防止由於複用而產生的顯示錯亂問題。
 *
 * @param recyclerView
 * @param viewHolder
 */
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
  //  super.clearView(recyclerView, viewHolder);
    //重置改變,防止由於複用而導致的顯示問題
    viewHolder.itemView.setScrollX(0);

    ((FormatListDialogAdapter.ViewHolder) viewHolder).tv_text.setText("左滑刪除");
}

/**
 * 我們可以在這個方法內實現我們自定義的互動規則或者自定義的動畫效果。
 *
 * @param c
 * @param recyclerView
 * @param viewHolder
 * @param dX
 * @param dY
 * @param actionState
 * @param isCurrentlyActive
 */
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
  //  super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);

    //僅對側滑狀態下的效果做出改變
    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;
            ((FormatListDialogAdapter.ViewHolder) viewHolder).tv_text.setText("鬆開刪除");   //把文字去掉

        }
    } else {
        //拖拽狀態下不做改變,需要呼叫父類的方法
        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;
}
}

第三步RecyclerView的介面卡實現ItemTouchHelperAdapter介面

    /**
 * 交換位置
 *
 * @param fromPosition
 * @param toPosition
 */
@Override
public void onItemMove(int fromPosition, int toPosition) {
    //交換位置
    Collections.swap(mCertificateList, fromPosition, toPosition);
    notifyItemMoved(fromPosition, toPosition);
}

/**
 * 移除資料
 *
 * @param position
 */
@Override
public void onItemDissmiss(int position) {

    //獲取到證書別名
    if (mCertificateList!=null&&mCertificateList.size()>=0){
        String alias = mCertificateList.get(position).getName();
        //刪除證書
        Config.getInstance().getProject().deleteCertificate(alias);
        //移除資料
        mCertificateList.remove(position);
        notifyItemRemoved(position);
    }
}

第四步實現RecyclerView與ItemTouchHelper的關聯

//先例項化Callback
ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(formatListDialogAdapter);
//用Callback構造ItemtouchHelper
ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
//呼叫ItemTouchHelper的attachToRecyclerView方法建立聯絡
touchHelper.attachToRecyclerView(certificateListRecyclerView);

到此已經實現了recyclerView的側滑刪除和拖拽排序.在onChildDraw方法中請自行修改動畫效果