Android -- RecyclerView實現左滑刪除


1,在實際項目中我們常常有對一個列表進行滑刪除操作,使用我們昨天的ItemTouchHelper其實也可以實現簡單的實現這個功能,先來看一下使用ItemTouchHelper來實現的效果:

2,從上面的效果圖我們可以看到,大致的實現了我們的需求,具體操作如下

  第一步 :添加表示為START和END標識位

            @Override
            public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
                if (recyclerView.getLayoutManager() instanceof GridLayoutManager) {
                    final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN |
                            ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
                    final int swipeFlags = 0;
                    return makeMovementFlags(dragFlags, swipeFlags);
                } else {
                    final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;

                    final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
                    return makeMovementFlags(dragFlags, swipeFlags);
                }
            }

  第二步 : 在側滑過程中刪除數據

            @Override
            public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
               int position = viewHolder.getAdapterPosition();
               myAdapter.notifyItemRemoved(position);
               datas.remove(position);
            }

  這樣就很簡單的實現了我們的操作

3,但是上面實現方法有一個短板,就是用戶有時候是不小心向左滑動,這樣我們最好在滑動后添加一個確定操作的按鈕,以確保用戶不是手誤滑動,這是我們要自定義RecyclerView重寫OnTouchEvent方法來實現,先看一下實現的效果:

  來說一下整體的思路

  第一步:RecyclerView的item布局是由兩部分組成,一是我們正常的item,還有一部分是我們還有刪除按鈕的布局文件,布局文件展示效果如下:

代碼如下:

item_linear.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="wrap_content"
              android:orientation="horizontal"
              android:id="@+id/ll_item"
    >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/tv_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_marginLeft="5dp"
            android:layout_weight="1"
            android:text="我是標題"
            android:textSize="16dp"/>

        <ImageView
            android:id="@+id/img"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="5dp"
            android:layout_marginTop="5dp"
            android:src="@mipmap/ic_category_0"
            />
    </LinearLayout>

    <!-- 屏幕右側外邊部分,正常時在屏幕中處於不可見 -->
    <LinearLayout
        android:id="@+id/ll_hidden"
        android:layout_width="50dp"
        android:layout_height="match_parent"
        android:background="#ff0000"
        android:gravity="center"
        >

        <TextView
            android:id="@+id/tv_item_delete"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="刪除"
            android:textColor="#ffffff"
            android:textSize="16sp"
            />
    </LinearLayout>
</LinearLayout>

  第二步:創建自定義的RecyclerView,重寫onTouchEvent()方法,而重寫OnTouchEvent()的大致思路是當用戶手指按下時,計算出當前選中的是哪個Item,並獲取到該Item對象;然后判斷手指移動方向,若左移,則滑動(在滑動之前,先恢復上次的狀態);若右移,則恢復;當左移完成之后,“刪除”按鈕自然就“暴露”在屏幕上可點擊的范圍了;然后就可以對Item進行刪除操作了。 由於代碼中的注釋很詳細了,就不再講解了

  SwipRecyclerView.java

package com.qianmo.dragrecyclerview;

import android.content.Context;
import android.graphics.Rect;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.animation.LinearInterpolator;
import android.widget.LinearLayout;
import android.widget.Scroller;
import android.widget.TextView;

/**
 * Created by Administrator on 2017/3/14 0014.
 * E-Mail:543441727@qq.com
 */

public class SwipeRecyclerView extends RecyclerView{

    private static final String TAG = "RecycleView";
    private int maxLength, mTouchSlop;
    private int xDown, yDown, xMove, yMove;
    /**
     * 當前選中的item索引(這個很重要)
     */
    private int curSelectPosition;
    private Scroller mScroller;

    private LinearLayout mCurItemLayout, mLastItemLayout;
    private LinearLayout mLlHidden;//隱藏部分
    private TextView mItemContent;
    private LinearLayout mItemDelete;

    /**
     * 隱藏部分長度
     */
    private int mHiddenWidth;
    /**
     * 記錄連續移動的長度
     */
    private int mMoveWidth = 0;
    /**
     * 是否是第一次touch
     */
    private boolean isFirst = true;
    private Context mContext;

    /**
     * 刪除的監聽事件
     */
    private OnRightClickListener mRightListener;

    public void setRightClickListener(OnRightClickListener listener){
        this.mRightListener = listener;
    }


    public SwipeRecyclerView(Context context) {
        this(context, null);
    }

    public SwipeRecyclerView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SwipeRecyclerView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mContext = context;
        //滑動到最小距離
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
        //滑動的最大距離
        maxLength = ((int) (180 * context.getResources().getDisplayMetrics().density + 0.5f));
        //初始化Scroller
        mScroller = new Scroller(context, new LinearInterpolator(context, null));
    }

    @Override
    public boolean onTouchEvent(MotionEvent e) {
        int x = (int)e.getX();
        int y = (int)e.getY();
        switch (e.getAction()){
            case MotionEvent.ACTION_DOWN:
                //記錄當前按下的坐標
                xDown = x;
                yDown = y;
                //計算選中哪個Item
                int firstPosition = ((LinearLayoutManager)getLayoutManager()).findFirstVisibleItemPosition();
                Rect itemRect = new Rect();

                final int count = getChildCount();
                for (int i=0; i<count; i++){
                    final View child = getChildAt(i);
                    if (child.getVisibility() == View.VISIBLE){
                        child.getHitRect(itemRect);
                        if (itemRect.contains(x, y)){
                            curSelectPosition = firstPosition + i;
                            break;
                        }
                    }
                }

                if (isFirst){//第一次時,不用重置上一次的Item
                    isFirst = false;
                }else {
                    //屏幕再次接收到點擊時,恢復上一次Item的狀態
                    if (mLastItemLayout != null && mMoveWidth > 0) {
                        //將Item右移,恢復原位
                        scrollRight(mLastItemLayout, (0 - mMoveWidth));
                        //清空變量
                        mHiddenWidth = 0;
                        mMoveWidth = 0;
                    }

                }

                //取到當前選中的Item,賦給mCurItemLayout,以便對其進行左移
                View item = getChildAt(curSelectPosition - firstPosition);
                if (item != null) {
                    //獲取當前選中的Item
                    MyAdapter.ViewHolder viewHolder = (MyAdapter.ViewHolder) getChildViewHolder(item);
                    mCurItemLayout = viewHolder.ll_item;
                    //找到具體元素(這與實際業務相關了~~)
                    mLlHidden = (LinearLayout)mCurItemLayout.findViewById(R.id.ll_hidden);
                    mItemDelete = (LinearLayout)mCurItemLayout.findViewById(R.id.ll_hidden);
                    mItemDelete.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            if (mRightListener != null){
                                //刪除
                                mRightListener.onRightClick(curSelectPosition, "");
                            }
                        }
                    });

                    //這里將刪除按鈕的寬度設為可以移動的距離
                    mHiddenWidth = mLlHidden.getWidth();
                }
                break;

            case MotionEvent.ACTION_MOVE:
                xMove = x;
                yMove = y;
                int dx = xMove - xDown;//為負時:手指向左滑動;為正時:手指向右滑動。這與Android的屏幕坐標定義有關
                int dy = yMove - yDown;//

                //左滑
                if (dx < 0 && Math.abs(dx) > mTouchSlop && Math.abs(dy) < mTouchSlop){
                    int newScrollX = Math.abs(dx);
                    if (mMoveWidth >= mHiddenWidth){//超過了,不能再移動了
                        newScrollX = 0;
                    } else if (mMoveWidth + newScrollX > mHiddenWidth){//這次要超了,
                        newScrollX = mHiddenWidth - mMoveWidth;
                    }
                    //左滑,每次滑動手指移動的距離
                    scrollLeft(mCurItemLayout, newScrollX);
                    //對移動的距離疊加
                    mMoveWidth = mMoveWidth + newScrollX;
                }else if (dx > 0){//右滑
                    //執行右滑,這里沒有做跟隨,瞬間恢復
                    scrollRight(mCurItemLayout, 0 - mMoveWidth);
                    mMoveWidth = 0;
                }

                break;
            case MotionEvent.ACTION_UP://手抬起時
                int scrollX = mCurItemLayout.getScrollX();

                if (mHiddenWidth > mMoveWidth) {
                    int toX = (mHiddenWidth - mMoveWidth);
                    if (scrollX > mHiddenWidth / 2) {//超過一半長度時松開,則自動滑到左側
                        scrollLeft(mCurItemLayout, toX);
                        mMoveWidth = mHiddenWidth;
                    } else {//不到一半時松開,則恢復原狀
                        scrollRight(mCurItemLayout, 0 - mMoveWidth);
                        mMoveWidth = 0;
                    }
                }
                mLastItemLayout = mCurItemLayout;
                break;


        }
        return super.onTouchEvent(e);
    }


    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {

            Log.e(TAG, "computeScroll getCurrX ->" + mScroller.getCurrX());
            mCurItemLayout.scrollBy(mScroller.getCurrX(), 0);
            invalidate();
        }
    }

    /**
     * 向左滑動
     */
    private void scrollLeft(View item, int scorllX){
        Log.e(TAG, " scroll left -> " + scorllX);
        item.scrollBy(scorllX, 0);
    }

    /**
     * 向右滑動
     */
    private void scrollRight(View item, int scorllX){
        Log.e(TAG, " scroll right -> " + scorllX);
        item.scrollBy(scorllX, 0);
    }

    public interface OnRightClickListener{
        void onRightClick(int position, String id);
    }
}

  這樣我們就實現了給RecyclerView添加左滑刪除了 ,這是GitHub下載鏈接  See You Next Time !


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM