自定義RecyclerView實現側滑刪除

maweiliang發表於2017-05-10

前言:

  專案原始碼下載地址:download.csdn.net/detail/mtx_…
  此篇主要是通過自動以RecyclerView,同過scrollTo()、Scroller來實現左劃刪除功能。

1.基礎知識引入

scrollTo(int x,inty):
它是View中的方法,可以對View中的內容進行滾動,強調一下滑動的是view的“內容”,scrollTo()是讓View相對於初始的位置滾動某段距離

RecyclerView實現左劃刪除

首選我來看Item的佈局檔案Recycler_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/item_root"
    >
 <TextView
     android:id="@+id/item_text"
     android:layout_width="match_parent"
     android:layout_height="40dp"
     android:layout_gravity="center"
     android:gravity="center"
     android:text="text" />

 <TextView
     android:id="@+id/item_del"
     android:layout_width="100dp"
     android:layout_height="fill_parent"
     android:background="#EE2C2C"
     android:text="刪除"
     android:textSize="25dp"
     android:gravity="center" />
</LinearLayout>複製程式碼

item有兩個水平的textView檔案組成,第一個TextView是我們正常顯示的Item,它的寬度佔滿螢幕,第二TextView就是我們的刪除按鈕,它被隱藏在螢幕之外。下面在看看Adapter部分CustomAdapter.java。

public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.CustomViewHolder> {
    private List<String> mDatas;

    public CustomAdapter(List<String> mDatas, Context mContext) {
        this.mDatas = mDatas;
    }

    @Override
    public CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item, parent, false);
        return new CustomViewHolder(view);
    }

    @Override
    public void onBindViewHolder(final CustomViewHolder holder, final int position) {
        holder.textView.setText(mDatas.get(position));
    }

    @Override
    public int getItemCount() {
        return mDatas.size();
    }

    class CustomViewHolder extends RecyclerView.ViewHolder {
        TextView textView;
        TextView deleteView;

        public CustomViewHolder(View itemView) {
            super(itemView);
            textView = (TextView) itemView.findViewById(R.id.item_text);
            deleteView = (TextView) itemView.findViewById(R.id.item_del);
        }
    }
}複製程式碼

這個比較簡單,沒啥可說的,下面我來來看看我的重點部分自定義的CustomRecyclerView類的實現

public class CustomRecyclerView extends RecyclerView{
    //item的根佈局
    private LinearLayout itemRoot;
    //上一次滑動的Item根佈局
    private LinearLayout itemRootLast;
    //上次X軸的滑動座標
    private int mlastX = 0;
    //上次Y軸的滑動座標
    private int mlastY = 0;
    //滑動的最大距離
    private final int MAX_WIDTH = 100;
    private Context mContext;
    private Scroller mScroller;

    public CustomRecyclerView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
        mScroller = new Scroller(context, new LinearInterpolator(context, null));
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int maxLength = dipToPx(mContext, MAX_WIDTH);
        int x = (int) event.getX();
        int y = (int) event.getY();
        final int  position;
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                //恢復上一次側滑的ITEM
                if(itemRootLast !=null){
                    itemRootLast.scrollTo(0, 0);
                    invalidate();
                }
                //根據點選的座標獲取那個Item被點選了
                View view  = findChildViewUnder(x, y);
                if(view == null){
                    return false;
                }
                final CustomAdapter.CustomViewHolder viewHolder = (CustomAdapter.CustomViewHolder) getChildViewHolder(view);
                itemRootLast = itemRoot = (LinearLayout) viewHolder.textView.getParent();

                 position= viewHolder.getAdapterPosition();
                if(mOnItemClickListener !=null){
                    viewHolder.deleteView.setOnClickListener(new OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            mOnItemClickListener.onClick(viewHolder.itemView,position);
                        }
                    });
                }
            }
            break;
            case MotionEvent.ACTION_MOVE: {
                if(itemRoot ==null){
                    return  false;
                }
                if(  Math.abs(mlastX -x)>0 && Math.abs(mlastX -x) > Math.abs(mlastY-y)){
                    int scrollX = itemRoot.getScrollX();
                    int newScrollX = scrollX + mlastX - x;
                    if (newScrollX < 0) {
                        newScrollX = 0;
                    } else if (newScrollX > maxLength) {
                        newScrollX = maxLength;
                    }
                    itemRoot.scrollTo(newScrollX, 0);
                }


            }
            break;
            case MotionEvent.ACTION_UP: {
                if(itemRoot ==null){
                    return  false;
                }
                int scrollX = itemRoot.getScrollX();
                int newScrollX = scrollX + mlastX - x;
                if (scrollX > maxLength / 2) {
                    newScrollX = maxLength;
                } else {
                    newScrollX = 0;
                }
                mScroller.startScroll(scrollX, 0, newScrollX - scrollX, 0);
                invalidate();
            }
            break;
        }
        mlastX = x;
        mlastY = y;
        return super.onTouchEvent(event);
    }

    private int dipToPx(Context context, int dip) {
        return (int) (dip * context.getResources().getDisplayMetrics().density + 0.5f);
    }

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            itemRoot.scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            if(itemRootLast !=null){
                itemRootLast.scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            }
        }
        invalidate();
    }

    private OnItemClickListener mOnItemClickListener;
    public interface OnItemClickListener{
        void onClick(View view,int position);
    }

    public  void setOnItemClickListenre(OnItemClickListener mOnItemClickListener){
        this.mOnItemClickListener = mOnItemClickListener;
    }
}複製程式碼

我來來詳細看一下上面的程式碼:

自定義RecyclerView實現側滑刪除

首選在MotionEvent.ACTION_DOWN事件發生時,如果上次有Item已經側滑出了,這裡就讓它恢復正常的顯示,接著看
自定義RecyclerView實現側滑刪除
我們通過findChildViewUnder(x, y)方法來實現根據當前點選的座標值,得到被點選的Item的view,這一步是很關鍵的,接著我們通過剛才得到view獲取到我們的viewHolder物件,拿到它我們就好辦了,我們就可以得到點選Item的position等。
自定義RecyclerView實現側滑刪除

我們在MotionEvent.ACTION_MOVE事件中去根據手指滑動的距離來實時處理View的滑動
自定義RecyclerView實現側滑刪除

MotionEvent.ACTION_UP事件中,如果此時滑動的距離大於最大滑動距離的一半,我們就讓整個按鈕都滑動出來,反之我就讓它恢復原來的狀態.
自定義RecyclerView實現側滑刪除

刪除按鈕監聽在ACTION_DOWN事件中繫結監聽事件即可,監聽介面如下
自定義RecyclerView實現側滑刪除

我們在MainActivity中實現給就可就Ok了
自定義RecyclerView實現側滑刪除

專案原始碼下載地址:download.csdn.net/detail/mtx_…

相關文章