当前位置: 移动技术网 > IT编程>移动开发>Android > Android仿QQ列表左滑删除操作

Android仿QQ列表左滑删除操作

2019年07月24日  | 移动技术网IT编程  | 我要评论

表白情书怎么写,haole,致命魔术迅雷下载

最近学习了如何做一个像qq的左滑recyclerview的item显示选项的,主要是用到scroller

我们首先新建一个自己的recyclerview

定义好一些要用的的变量
重写构造方法,把前两个构造方法改为如下,使无论如何构造都要执行第三个构造方法
在第三个构造方法里初始化scroller

public class leftswipemenurecyclerview extends recyclerview {

  //置顶按钮
  private textview tvtop;
  //删除按钮
  private textview tvdelete;
  //item相应的布局
  private linearlayout mitemlayout;
  //菜单的最大宽度
  private int mmaxlength;

  //上一次触摸行为的x坐标
  private int mlastx;
  //上一次触摸行为的y坐标
  private int mlasty;

  //当前触摸的item的位置
  private int mposition;

  //是否在垂直滑动列表
  private boolean isdragging;
  //item是在否跟随手指移动
  private boolean isitemmoving;
  //item是否开始自动滑动
  private boolean isstartscroll;

  //左滑菜单状态  0:关闭 1:将要关闭 2:将要打开 3:打开
  private int mmenustate;
  private static int menu_closed = 0;
  private static int menu_will_closed = 1;
  private static int menu_open = 2;
  private static int menu_will_open = 3;

  //实现弹性滑动,恢复
  private scroller mscroller;

  //item的事件监听
  private onitemactionlistener mlistener;

  public leftswipemenurecyclerview(context context) {
    this(context, null);
  }

  public leftswipemenurecyclerview(context context, @nullable attributeset attrs) {
    this(context, attrs, 0);
  }

  public leftswipemenurecyclerview(context context, @nullable attributeset attrs, int defstyle) {
    super(context, attrs, defstyle);
    mscroller = new scroller(context, new linearinterpolator());
  }

重写ontouchevent方法

event主要有以下几个action

  • action_down 手指接触到屏幕
  • action_move 手指在屏幕滑动
  • action_up 手指离开屏幕

一开始肯定要获取x和y的相对坐标

int x= (int) event.getx();
int y= (int) event.gety();

然后接下来分别处理3个不同的行为

1.action_down

case motionevent.action_down:
        if (mmenustate == menu_closed) {
          //根据坐标获得view
          view view = findchildviewunder(x, y);
          if (view == null) {
            return false;
          }
          //获得这个view的viewholder
          rvadapter.holder holder = (rvadapter.holder) getchildviewholder(view);
          //获得这个view的position
          mposition = holder.getadapterposition();
          //获得这个view的整个布局
          mitemlayout = holder.lllayout;
          //获得这个view的删除按钮
          tvdelete = holder.tvdelete;
          //这个view的整个置顶按钮
          tvtop = holder.tvtop;
          //两个按钮的宽度
          mmaxlength = tvdelete.getwidth() + tvtop.getwidth();

          //设置删除按钮点击监听
          tvdelete.setonclicklistener(new onclicklistener() {
            @override
            public void onclick(view view) {
              mitemlayout.scrollto(0, 0);
              mmenustate =menu_closed;
              mlistener.onitemdelete(mposition);
            }
          });
          //设置置顶按钮点击监听
          tvtop.setonclicklistener(new onclicklistener() {
            @override
            public void onclick(view view) {
              mitemlayout.scrollto(0, 0);
              mmenustate =menu_closed;
              mlistener.onitemtop(mposition);
            }
          });
          //如果是打开状态,点击其他就把当前menu关闭掉
        } else if (mmenustate == menu_open) {
          mscroller.startscroll(mitemlayout.getscrollx(), 0, -mmaxlength, 0, 200);
          invalidate();
          mmenustate = menu_closed;
          //该点击无效
          return false;
        } else {
          return false;
        }
        break;

2.action_move

      case motionevent.action_move:
        //计算偏移量
        int dx = mlastx - x;
        int dy = mlasty - y;
        //当前滑动的x
        int scrollx = mitemlayout.getscrollx();

        if (math.abs(dx) > math.abs(dy)) {

          isitemmoving = true;
          //超出左边界则始终保持不动
          if (scrollx + dx <= 0) {
            mitemlayout.scrollto(0, 0);
            //滑动无效
            return false;
          //超出右边界则始终保持不动
          } else if (scrollx + dx >= mmaxlength) {
            mitemlayout.scrollto(mmaxlength, 0);
            //滑动无效
            return false;
          }
          //菜单随着手指移动
          mitemlayout.scrollby(dx, 0);
        //如果水平移动距离大于30像素的话,recyclerview不会上下滑动
        }else if (math.abs(dx) > 30){
          return true;
        }
        //如果菜单正在打开就不能上下滑动
        if (isitemmoving){
          mlastx = x;
          mlasty = y;
          return true;
        }
        break;

3.action_up

case motionevent.action_up:
        //手指抬起时判断是否点击,静止且有listener才能点击
        if (!isitemmoving && !isdragging && mlistener != null) {
          mlistener.onitemclick(mposition);
        }
        isitemmoving = false;

        //等一下要移动的距离
        int deltax = 0;
        int upscrollx = mitemlayout.getscrollx();
        //滑动距离大于1/2menu长度就自动展开,否则就关掉
        if (upscrollx >= mmaxlength / 2) {
          deltax = mmaxlength - upscrollx;
          mmenustate = menu_will_open;
        } else if (upscrollx < mmaxlength / 2) {
          deltax = -upscrollx;
          mmenustate = menu_will_closed;
        }
        //知道我们为什么不直接把mmenustate赋值为menu_open或者menu_closed吗?因为滑动时有时间的,我们可以在滑动完成时才把状态改为已经完成
        mscroller.startscroll(upscrollx, 0, deltax, 0, 200);
        isstartscroll = true;
        //刷新界面
        invalidate();
        break;

之后还要在ontouchevent方法里刷新坐标

   //只有更新mlastx,mlasty数据才会准确
    mlastx = x;
    mlasty = y;
    return super.ontouchevent(e);

因为我们用到了startscroll所以要重写computescroll方法

  public void computescroll() {
    //判断scroller是否完成滑动
    if (mscroller.computescrolloffset()) {
      mitemlayout.scrollto(mscroller.getcurrx(), mscroller.getcurry());
      //这个很重要
      invalidate();
    //如果已经完成就改变状态
    } else if (isstartscroll) {
      isstartscroll = false;
      if (mmenustate == menu_will_closed) {
        mmenustate = menu_closed;
      }
      if (mmenustate == menu_will_open) {
        mmenustate = menu_open;
      }
    }
  }

**还要监听recyclerview是否在上下滑动

 @override
  public void onscrollstatechanged(int state) {
    super.onscrollstatechanged(state);
    //是否在上下滑动
    isdragging = state == scroll_state_dragging;
  }

还要设置listener

//设置listener
  public void setonitemactionlistener(onitemactionlistener onitemactionlistener) {
    this.mlistener = onitemactionlistener;
  }

这个listener是要自己新建的

public interface onitemactionlistener {
  void onitemclick(int position);
  void onitemtop(int position);
  void onitemdelete(int position);
}

最后是点击,置顶,删除在activity里的回调

这里只展示回调实现部分,我这里用的list是linkedlist,可以在第一位添加数据

rv.setonitemactionlistener(new onitemactionlistener() {
      //点击
      @override
      public void onitemclick(int position) {
        toast.maketext(mainactivity.this,"click"+position,toast.length_short).show();
      }
      //置顶
      @override
      public void onitemtop(int position) {
        //获得当前位置的内容
        string temp =list.get(position);
        //移除这个item
        list.remove(position);
        //把它添加到第一个
        list.addfirst(temp);
        //更新数据源
        adapter.notifydatasetchanged();
      }
      //删除
      @override
      public void onitemdelete(int position) {
        list.remove(position);
        //更新数据源
        adapter.notifydatasetchanged();
      }
    });

adapter和布局的代码太简单我就不放出来了,大家可以到源码里看看有什么

效果图

源码地址:https://github.com/jkgeekjack/slideleftmenurecyclerview

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网