recycleview左滑删除item实现

Recycleview左滑删除item:

首先要理解:scrollTo(),scrollBy(),getScrollX(),getScrollY()
recycleview左滑删除item实现_第1张图片
整个坐标系是以手机屏幕左上角为为原点,子视图的高度应该和手机屏幕高度一样高。

public voidscrollTo(int x,int y):它表示移动到视图的那个坐标点,哪个视图调用这个方法,那么这个视图的(x,y)点就与手机屏幕的左上角对齐(手机屏幕的左上角就移动到(x,y)坐标)。
public voidscrollBy(int dx,int dy):它表示在视图的X,Y方向上各移动dx,dy距离 dx>0表示视图(View或ViewGroup)的内容从右向左滑动;反之,从左向右滑动
dy>0表示视图(View或ViewGroup)的内容从下向上滑动;反之,从上向下滑动。
getScrollX():屏幕原点X坐标减去调用视图左上角X坐标,例如红色图得到的为o-(-320) = 320;
getScrollY();屏幕原点Y坐标减去调用视图左上角Y坐标,例如红色图得到的为0-0=0;
知道上面几个方法后,可以开始实现了。
总体思想:
其实删除无非是调用removeItem(int position)将适配器中的list的指定项remove,然后再notifyDataSetChanged(),难在于滑动的操作。
自定义recycleview.重写onTouchEvent(MotionEvent e)方法:处理手指触摸到移动最后到离开屏幕的事件 。重写computeScroll()方法:当执行ontouch 或invalidate 或postInvalidate()都会导致这个方法的执行。

首先先上效果图:

recycleview左滑删除item实现_第2张图片
1.item的布局设计是,最外层一定要LinearLayout并且设竖直排列方式,主体内容撑满整个布局,删除按钮要在主体内容的右边(删除按钮在布局外)。
item的布局为:



    //主体item内容
    

        

        

    

   //删除按钮(TextView)
    



具体自定义recycleview的实现如下:

/**
 * Created by lu on 2017/11/6.
 */

public class MyCustomRecycleView extends RecyclerView {

    private Context mContext;
    //上一次的触摸点
    private int mLastX,mLastY;
    //当前触摸的item的位置
    private int mPosition;
    //item对应的布局
    private LinearLayout mItemLayout;
    //删除按钮
    private TextView mDelete;
    //最大滑动距离(即删除按钮的宽度)
    private int mMaxLength;
    //是否在垂直滑动列表
    private boolean isDragging;
    //item是在否跟随手指移动
    private boolean isItemMoving;
    //item是否开始自动滑动
    private boolean isStartScroll;
    //删除按钮状态 0:关闭 1:将要关闭 2:将要打开 3:打开
    private int mDeleteBtnState;
    //检测手指在滑动过程中的速度
    private VelocityTracker mVelocityTracker;
    private Scroller mScroller;//处理滚动效果的工具类,实现View平滑滚动的一个Helper类
    private OnItemClickListener mListener;
    public MyCustomRecycleView(Context context) {
        this(context,null);
    }
    public MyCustomRecycleView(Context context, @Nullable AttributeSet attrs){
        this(context,attrs,0);
    }
    public MyCustomRecycleView(Context context,@Nullable AttributeSet attrs,int defStyle){
       super(context,attrs,defStyle);
       mContext = context;
        //初始化
       mScroller = new Scroller(context,new LinearInterpolator());
       // 1.当开始追踪的时候,使用obtain来获取VelocityTracker类的实例
       mVelocityTracker = VelocityTracker.obtain();
    }
    @Override
    public boolean onTouchEvent(MotionEvent e){
    //向VelocityTracker添加MotionEvent
        mVelocityTracker.addMovement(e);
        int x = (int) e.getX();
        int y = (int) e.getY();
        switch(e.getAction()) {
            case MotionEvent.ACTION_DOWN://松开

               if(mDeleteBtnState == 0){//删除按钮为关闭
                   View view = findChildViewUnder(x,y);//返回指定位置的view
                   if(view == null){
                       return false;
                   }
                   //得到需要删除的view
                   MyAdapter.MyHolder viewHolder = (MyAdapter.MyHolder)getChildViewHolder(view);
                   //获取根布局
                   if(viewHolder.layout !=null){
                       mItemLayout = viewHolder.layout;
                       //触摸item的位置
                       mPosition = viewHolder.getAdapterPosition();
                       mDelete = (TextView)mItemLayout.findViewById(R.id.item_delete);
                       mMaxLength = mDelete.getWidth();
                       mDelete.setOnClickListener(new OnClickListener() {
                           @Override
                           public void onClick(View v) {
                               mListener .onDeleteClick(mPosition);
                               mItemLayout.scrollTo(0,0);
                               mDeleteBtnState = 0;//关闭
                           }
                       });
                   }else{
                       return false;
                   }

               }else if(mDeleteBtnState == 3){//按钮状态是打开的
                   //开始一个动画控制,由(mItemLayout.getScrollX() , 0)在200时间内前进(-mMaxLength,0)个单位,即到达坐标为(mItemLayout.getScrollX()-mMaxLength , 0)
                   mScroller.startScroll(mItemLayout.getScrollX(),0,-mMaxLength,0,200);
                   invalidate();//重绘
                   mDeleteBtnState = 0;//按钮变为关闭
                   return false;
               }else{
                   return false;
               }
               break;
            case MotionEvent.ACTION_MOVE:
                int dx = mLastX -x;
                int dy =mLastY -y;
                //返回当前滑动View左边界的位置
                int scrollx = mItemLayout.getScrollX();
                if(Math.abs(dx) > Math.abs(dy)){//左边界检测,要有足够的滑动距离
                  isItemMoving = true;
                    if(scrollx + dx <= 0){//滑动距离不够
                        mItemLayout.scrollTo(0,0);//移动到原点
                        return true;
                    }else if(scrollx + dx >= mMaxLength){//右边界检测,往右边滑动大于能滑动距离
                        mItemLayout.scrollTo(mMaxLength, 0);
                        return true;
                    }
                    mItemLayout.scrollBy(dx, 0);//item跟随手指滑动
                }

                break;
            case MotionEvent.ACTION_UP:
                //没有移动 不在垂直滑动列表 监听不为空
                if (!isItemMoving && !isDragging && mListener != null) {
                    mListener.onItemclick(mItemLayout, mPosition);
                }
                isItemMoving = false;

                mVelocityTracker.computeCurrentVelocity(1000);//计算手指滑动的速度
                float xVelocity = mVelocityTracker.getXVelocity();//水平方向速度(向左为负)
                float yVelocity = mVelocityTracker.getYVelocity();//垂直方向速度

                int deltaX = 0;//到达的X坐标
                int upScrollX = mItemLayout.getScrollX();//手指离开屏幕时item的左上角x坐标
                if(Math.abs(xVelocity) > 100 && Math.abs(xVelocity) > Math.abs(yVelocity)){
                   if(xVelocity <= -100){//左滑速度大于100,则删除按钮显示
                       deltaX = mMaxLength - upScrollX;
                       mDeleteBtnState = 2;//删除按钮即将打开
                   }else if(xVelocity > 100){//右滑速度大于100,则删除按钮隐藏
                       deltaX = -upScrollX;
                       mDeleteBtnState = 1;//删除按钮将要关闭
                   }
                }else{
                  if(upScrollX >= mMaxLength / 2){//item的左滑动距离大于删除按钮宽度的一半,则显示删除按钮
                      deltaX = mMaxLength - upScrollX;
                      mDeleteBtnState = 2;//删除按钮即将打开
                  }else if(upScrollX < mMaxLength / 2){//否则隐藏
                      deltaX = -upScrollX;
                      mDeleteBtnState = 1;//删除按钮即将关闭
                  }
                }
                //item由手指离开屏幕的位置 滚动,upScrollX, 0为开始滚动的位置,deltaX,0为滚动的偏移量, duration为完成滚动的时间 默认为250
                mScroller.startScroll(upScrollX, 0, deltaX, 0, 200);
                isStartScroll = true;
                invalidate();

                mVelocityTracker.clear();
                break;

        }
        mLastX = x;
        mLastY = y;
        return super.onTouchEvent(e);
    }
    //当我们执行ontouch或invalidate()或postInvalidate()都会导致这个方法的执行
    @Override
    public void computeScroll(){
        //先判断mScroller滚动是否完成
        if (mScroller.computeScrollOffset()) {
            //这里调用View的scrollTo()完成实际的滚动
            mItemLayout.scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            invalidate();
        } else if (isStartScroll) {//滚动没有完成
            isStartScroll = false;
            if (mDeleteBtnState == 1) {//将要关闭
                mDeleteBtnState = 0;//变为关闭
            }

            if (mDeleteBtnState == 2) {//将要打开
                mDeleteBtnState = 3;//打开
            }
        }
    }
  //  在destroy view的时候调用,所以可以加入取消广播注册等的操作
    @Override
    protected void onDetachedFromWindow() {
        mVelocityTracker.recycle();
        super.onDetachedFromWindow();
    }
    //监听滑动状态
    @Override
    public void onScrollStateChanged(int state) {
        super.onScrollStateChanged(state);
        isDragging = state == SCROLL_STATE_DRAGGING;
    }

    public interface OnItemClickListener{
        /**
         *
         * item点击回调
         */
        void onItemclick(View view,int position);
        /**
         *
         * 删除按钮的回调
         */
        void onDeleteClick(int position);
    }

    public void setOnItemClickListen(OnItemClickListener listener){
        mListener = listener;

    }
}
调用的时候:
    mrecycler.setOnItemClickListen(new MyCustomRecycleView.OnItemClickListener() {
            @Override
            public void onItemclick(View view, int position) {

            }

            @Override
            public void onDeleteClick(int position) {
                if(position != madapter.getItemCount()){
                    if(madapter.haveHeaderView()){
                        madapter.removeItem(position-1);
                    }else{
                        madapter.removeItem(position);
                    }
                }else{
                    if(madapter.havaFooterView()){
                        madapter.removeItem(position-1);
                    }else{
                        madapter.removeItem(position);
                    }
                }


            }
        });
    }

有头部的时候要减1,有尾部也要减1,默认头部和尾部加在第一位和最后一位。

项目地址: 点击打开链接


你可能感兴趣的:(recycleview左滑删除item实现)