Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android仿QQ列表左滑刪除操作

Android仿QQ列表左滑刪除操作

編輯:關於Android編程

最近學習了如何做一個像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

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持本站。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved