Android仿QQ列表左滑删除操作

最近学习了如何做一个像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

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

(0)

相关推荐

  • Android自定义ListView实现仿QQ可拖拽列表功能

    我们大致的思路,其实是这样子的,也是我的设想,我们可以先去实现一个简单的ListView的数据,但是他的Adapter,我们可以用系统封装好的,然后传递进去一个实体类,最后自定义一个listview去操作,所以我们先把准备的工作做好,比如? list_item.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.a

  • android开发教程之使用listview显示qq联系人列表

    首先还是xml布局文件,在其中添加ListView控件: 主布局layout_main.xml 复制代码 代码如下: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"

  • android编程实现悬浮窗体的方法

    本文实例讲述了android编程实现悬浮窗体的方法.分享给大家供大家参考,具体如下: 突然对悬浮窗体感兴趣,查资料做了个小Demo,效果是点击按钮后,关闭当前Activity,显示悬浮窗口,窗口可以拖动,双击后消失.效果图如下: 它的使用原理很简单,就是借用了WindowManager这个管理类来实现的. 1.首先在AndroidManifest.xml中添加使用权限: 复制代码 代码如下: <uses-permission android:name="android.permission

  • Android实现桌面悬浮窗、蒙板效果实例代码

    现在很多安全类的软件,比如360手机助手,百度手机助手等等,都有一个悬浮窗,可以飘浮在桌面上,方便用户使用一些常用的操作. 今天这篇文章,就是介绍如何实现桌面悬浮窗效果的. 首先,看一下效果图. 悬浮窗一共分为两个部分,一个是平常显示的小窗口,另外一个是点击小窗口显示出来的二级悬浮窗口. 首先,先看一下这个项目的目录结构. 最关键的就是红框内的四个类. 首先,FloatWindowService是一个后台的服务类,主要负责在后台不断的刷新桌面上的小悬浮窗口,否则会导致更换界面之后,悬浮窗口也会随

  • Android仿QQ好友列表分组实现增删改及持久化

    Android自带的控件ExpandableListView实现了分组列表功能,本案例在此基础上进行优化,为此控件添加增删改分组及子项的功能,以及列表数据的持久化. Demo实现效果: GroupListDemo具体实现: ①demo中将列表页面设计为Fragment页面,方便后期调用:在主界面MainActivity中动态添加GroupListFragment页面: MainActivity.java package com.eric.grouplistdemo; import android

  • Android仿QQ好友列表实现列表收缩与展开

    ExpandableListView是一个垂直滚动显示两级列表项的视图,与ListView不同的是,它可以有两层:每一层都能够被独立的展开并显示其子项. 好友QQ列表,可以展开,可以收起,在android中,以往用的比较多的是listview,虽然可以实现列表的展示,但在某些情况下,我们还是希望用到可以分组并实现收缩的列表,那就要用到android的ExpandableListView,今天研究了一下这个的用法,也参考了很多资料动手写了一个小demo,实现了基本的功能,下面直接上效果图以及源代码

  • Android开发悬浮按钮 Floating ActionButton的实现方法

    一.介绍 这个类是继承自ImageView的,所以对于这个控件我们可以使用ImageView的所有属性 android.support.design.widget.FloatingActionButton 二.使用准备, 在as 的 build.grade文件中写上 compile 'com.android.support:design:22.2.0' 三.使用说明 xml文件中,注意蓝色字体部分 <android.support.design.widget.FloatingActionButt

  • android 添加随意拖动的桌面悬浮窗口

    用过新版本android 360手机助手都人都对 360中只在桌面显示一个小小悬浮窗口羡慕不已吧? 其实实现这种功能,主要有两步: 1.判断当前显示的是为桌面.这个内容我在前面的帖子里面已经有过介绍,如果还没看过的赶快稳步看一下哦. 2.使用windowManager往最顶层添加一个View .这个知识点就是为本文主要讲解的内容哦.在本文的讲解中,我们还会讲到下面的知识点: a.如果获取到状态栏的高度 b.悬浮窗口的拖动 c.悬浮窗口的点击事件 有开始之前,我们先来看一下效果图:  接下来我们来

  • Android UI仿QQ好友列表分组悬浮效果

    本文实例为大家分享了Android UI仿QQ好友列表分组悬浮效果的具体代码,供大家参考,具体内容如下 楼主是在平板上測试的.图片略微有点大,大家看看效果就好 接下来贴源代码: PinnedHeaderExpandableListView.java 要注意的是 在 onGroupClick方法中parent.setSelectedGroup(groupPosition)这句代码的作用是点击分组置顶, 我这边不须要这个效果.QQ也没实用到,所以给凝视了.大家假设须要能够解开凝视 package c

  • Android实现类似360,QQ管家那样的悬浮窗

    一.前言: 我手机从来不装这些东西,不过,有次看到同事的android手机上,有个QQ管家在桌面上浮着,同事拖动管家时,管家就变成一只鸟,桌面下方还有个弹弓,桌面顶部有只乌鸦,把管家也就是鸟拖动到弹弓那,然后,松手,鸟就飞出去.这个过程是动画过程,做的事,实际上是清楚内存. 二:原理: 其实,没什么原理,用到的就是WindowManager以及WindowManager.LayoutParams,对这个LayoutParams做文章,当设置为属性后,然后,创建一个View,将这个View添加到W

随机推荐