Android開發 RecyclerView實現拖動與滑動ItemTouchHelper

前言

  RecyclerView依靠ItemTouchHelper,實現item的拖動與滑動功能。

使用ItemTouchHelper實現上下拖動的例子

 

首先我們需要繼承重寫 ItemTouchHelper.Callback

 

複製代碼
public class QuickReplyItemTouchCallback extends ItemTouchHelper.Callback {
    private QuickReplyAdapter mAdapter;
    private boolean mIsLongPressDragEnabled = true;

    public QuickReplyItemTouchCallback(QuickReplyAdapter adapter) { //傳入適配器
        mAdapter = adapter;

    }

    public void setLongPressDragEnabled(boolean isLongPressDragEnabled) {
        mIsLongPressDragEnabled = isLongPressDragEnabled;
    }


    @Override
    public boolean isItemViewSwipeEnabled() { //是否啓用左右滑動
        return false;
    }

    @Override
    public boolean isLongPressDragEnabled() { //返回設置是否長按拖動Item上下移動
        return mIsLongPressDragEnabled;
    }

    @Override
    public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
        //在這個回調方法裏我們返回我們需要的使用的動作功能
        int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;  //拖動  這裏設置的UP 與 DOWN 表示允許上下拖動
        int swipeFlags = ItemTouchHelper.ACTION_STATE_IDLE;         //滑動  這裏設置的ACTION_STATE_IDLE 表示我們將滑動動作設置爲空閒
        return makeMovementFlags(dragFlags, swipeFlags);
   
    }

    @Override
    public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
        //用於上下移動Item的回調方法,在這個方法裏我們要主動將Adapter裏的數據互相替換位置
        mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
        //返回 true表示我們已經將Adapter裏的數據互相替換位置
        return true;
    }

    @Override
    public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
        //因爲我們不需要處理滑動,所以此處不寫邏輯

    }
}
複製代碼

 

 

 

Adapter更換位置的實現

 

複製代碼
    /**
     * 提供給QuickReplyItemTouchCallback類使用的移動Item位置的方法
     * @param fromPosition
     * @param toPosition
     */
    public void onItemMove(int fromPosition, int toPosition) {
        Collections.swap(mList, fromPosition, toPosition);//更換我們數據List的位置
        notifyItemMoved(fromPosition, toPosition);     //更換Adapter Item的視圖位置
        if (mOnChangeDataPositionListener != null){
            mOnChangeDataPositionListener.onChange(mList);  
        }
    }
複製代碼

 

在Activity裏給RecyclerView添加ItemTouchHelper.Callback

 

複製代碼
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false);
        mQuickReplyRecyclerView.setLayoutManager(linearLayoutManager);
        mQuickReplyAdapter = new QuickReplyAdapter();
        mQuickReplyRecyclerView.setAdapter(mQuickReplyAdapter);
        mCallback = new QuickReplyItemTouchCallback(mQuickReplyAdapter);
        ItemTouchHelper itemTouchHelper = new ItemTouchHelper(mCallback);
        itemTouchHelper.attachToRecyclerView(mQuickReplyRecyclerView);
複製代碼

 

使用ItemTouchHelper實現左右滑動的例子

 

下面的這個例子是改變需要出現的View的寬度

 

複製代碼
public class SwitchListItemTouchCallback extends ItemTouchHelper.Callback {
    private int mWidth = 0;

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

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

    @Override
    public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
        int dragFlags = ItemTouchHelper.ACTION_STATE_IDLE;
        int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
        return makeMovementFlags(dragFlags, swipeFlags);
    }

    @Override
    public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
        return false;
    }

    @Override
    public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {

    }

    @Override
    public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
        if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {  //判斷活動狀態爲左右滑動
            Context context = recyclerView.getContext();
            if (mWidth == 0) {
                mWidth = UnitConversionUtil.dip2px(context, 80); //Button顯示後最大的寬度。這裏用了一個dp轉px工具類
            }
            if (dX == 0){ //有時候點擊也會被觸發成swipe,這裏判斷不發生偏移量就跳過
                return;
            }
            boolean isLeft = dX < 0;
            SwitchListAdapter.ViewHolder itemViewHolder = (SwitchListAdapter.ViewHolder) viewHolder;
            ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) itemViewHolder.mDeleteBtn.getLayoutParams();
            if (isLeft) {
                layoutParams.width = Math.min((int) Math.abs(dX), mWidth);
            } else {
                layoutParams.width = Math.max((int) (mWidth - dX), 0);
            }
            itemViewHolder.mDeleteBtn.setLayoutParams(layoutParams);
        } else {
            super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
        }

    }

    @Override
    public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
//        super.clearView(recyclerView, viewHolder);
    }
}
複製代碼

 

 滾動整個View來實現,這個效果的關鍵點是那個需要隱藏或者顯示的View 需要在父類佈局的外面

 

佈局例子:

 

關鍵點 app:layout_constraintLeft_toRightOf="parent"

 

複製代碼
    <ImageButton
        android:id="@+id/delete_btn"
        android:layout_width="80dp"
        android:layout_height="0dp"
        android:background="@color/color_text_yellow"
        android:src="@drawable/ic_delete_2"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toRightOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
複製代碼

 

代碼

 

複製代碼
    @Override
    public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
        if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
            Context context = recyclerView.getContext();
            if (mWidth == 0) {
                mWidth = UnitConversionUtil.dip2px(context, 80);
            }
            if (dX == 0){ //有時候點擊也會被觸發成swipe,這裏判斷不發生偏移量就跳過
                return;
            }
            boolean isLeft = dX < 0;
            SwitchListAdapter.ViewHolder itemViewHolder = (SwitchListAdapter.ViewHolder) viewHolder;
            if (isLeft) {
                itemViewHolder.rootView.setScrollX(Math.min((int) Math.abs(dX), mWidth));
            } else {
                itemViewHolder.rootView.setScrollX(Math.max((int) (mWidth - dX), 0));
            }
        } else {
            super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
        }

    }
複製代碼

 

 

 

End

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章