1,在實際項目中我們常常有對一個列表進行滑刪除操作,使用我們昨天的ItemTouchHelper其實也可以實現簡單的實現這個功能,先來看一下使用ItemTouchHelper來實現的效果:

2,從上面的效果圖我們可以看到,大致的實現了我們的需求,具體操作如下
第一步 :添加表示為START和END標識位
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
if (recyclerView.getLayoutManager() instanceof GridLayoutManager) {
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN |
ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
final int swipeFlags = 0;
return makeMovementFlags(dragFlags, swipeFlags);
} else {
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
return makeMovementFlags(dragFlags, swipeFlags);
}
}
第二步 : 在側滑過程中刪除數據
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
int position = viewHolder.getAdapterPosition();
myAdapter.notifyItemRemoved(position);
datas.remove(position);
}
這樣就很簡單的實現了我們的操作
3,但是上面實現方法有一個短板,就是用戶有時候是不小心向左滑動,這樣我們最好在滑動后添加一個確定操作的按鈕,以確保用戶不是手誤滑動,這是我們要自定義RecyclerView重寫OnTouchEvent方法來實現,先看一下實現的效果:

來說一下整體的思路
第一步:RecyclerView的item布局是由兩部分組成,一是我們正常的item,還有一部分是我們還有刪除按鈕的布局文件,布局文件展示效果如下:

代碼如下:
item_linear.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:id="@+id/ll_item"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="5dp"
android:layout_weight="1"
android:text="我是標題"
android:textSize="16dp"/>
<ImageView
android:id="@+id/img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:layout_marginTop="5dp"
android:src="@mipmap/ic_category_0"
/>
</LinearLayout>
<!-- 屏幕右側外邊部分,正常時在屏幕中處於不可見 -->
<LinearLayout
android:id="@+id/ll_hidden"
android:layout_width="50dp"
android:layout_height="match_parent"
android:background="#ff0000"
android:gravity="center"
>
<TextView
android:id="@+id/tv_item_delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="刪除"
android:textColor="#ffffff"
android:textSize="16sp"
/>
</LinearLayout>
</LinearLayout>
第二步:創建自定義的RecyclerView,重寫onTouchEvent()方法,而重寫OnTouchEvent()的大致思路是當用戶手指按下時,計算出當前選中的是哪個Item,並獲取到該Item對象;然后判斷手指移動方向,若左移,則滑動(在滑動之前,先恢復上次的狀態);若右移,則恢復;當左移完成之后,“刪除”按鈕自然就“暴露”在屏幕上可點擊的范圍了;然后就可以對Item進行刪除操作了。 由於代碼中的注釋很詳細了,就不再講解了
SwipRecyclerView.java
package com.qianmo.dragrecyclerview;
import android.content.Context;
import android.graphics.Rect;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.animation.LinearInterpolator;
import android.widget.LinearLayout;
import android.widget.Scroller;
import android.widget.TextView;
/**
* Created by Administrator on 2017/3/14 0014.
* E-Mail:543441727@qq.com
*/
public class SwipeRecyclerView extends RecyclerView{
private static final String TAG = "RecycleView";
private int maxLength, mTouchSlop;
private int xDown, yDown, xMove, yMove;
/**
* 當前選中的item索引(這個很重要)
*/
private int curSelectPosition;
private Scroller mScroller;
private LinearLayout mCurItemLayout, mLastItemLayout;
private LinearLayout mLlHidden;//隱藏部分
private TextView mItemContent;
private LinearLayout mItemDelete;
/**
* 隱藏部分長度
*/
private int mHiddenWidth;
/**
* 記錄連續移動的長度
*/
private int mMoveWidth = 0;
/**
* 是否是第一次touch
*/
private boolean isFirst = true;
private Context mContext;
/**
* 刪除的監聽事件
*/
private OnRightClickListener mRightListener;
public void setRightClickListener(OnRightClickListener listener){
this.mRightListener = listener;
}
public SwipeRecyclerView(Context context) {
this(context, null);
}
public SwipeRecyclerView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SwipeRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mContext = context;
//滑動到最小距離
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
//滑動的最大距離
maxLength = ((int) (180 * context.getResources().getDisplayMetrics().density + 0.5f));
//初始化Scroller
mScroller = new Scroller(context, new LinearInterpolator(context, null));
}
@Override
public boolean onTouchEvent(MotionEvent e) {
int x = (int)e.getX();
int y = (int)e.getY();
switch (e.getAction()){
case MotionEvent.ACTION_DOWN:
//記錄當前按下的坐標
xDown = x;
yDown = y;
//計算選中哪個Item
int firstPosition = ((LinearLayoutManager)getLayoutManager()).findFirstVisibleItemPosition();
Rect itemRect = new Rect();
final int count = getChildCount();
for (int i=0; i<count; i++){
final View child = getChildAt(i);
if (child.getVisibility() == View.VISIBLE){
child.getHitRect(itemRect);
if (itemRect.contains(x, y)){
curSelectPosition = firstPosition + i;
break;
}
}
}
if (isFirst){//第一次時,不用重置上一次的Item
isFirst = false;
}else {
//屏幕再次接收到點擊時,恢復上一次Item的狀態
if (mLastItemLayout != null && mMoveWidth > 0) {
//將Item右移,恢復原位
scrollRight(mLastItemLayout, (0 - mMoveWidth));
//清空變量
mHiddenWidth = 0;
mMoveWidth = 0;
}
}
//取到當前選中的Item,賦給mCurItemLayout,以便對其進行左移
View item = getChildAt(curSelectPosition - firstPosition);
if (item != null) {
//獲取當前選中的Item
MyAdapter.ViewHolder viewHolder = (MyAdapter.ViewHolder) getChildViewHolder(item);
mCurItemLayout = viewHolder.ll_item;
//找到具體元素(這與實際業務相關了~~)
mLlHidden = (LinearLayout)mCurItemLayout.findViewById(R.id.ll_hidden);
mItemDelete = (LinearLayout)mCurItemLayout.findViewById(R.id.ll_hidden);
mItemDelete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mRightListener != null){
//刪除
mRightListener.onRightClick(curSelectPosition, "");
}
}
});
//這里將刪除按鈕的寬度設為可以移動的距離
mHiddenWidth = mLlHidden.getWidth();
}
break;
case MotionEvent.ACTION_MOVE:
xMove = x;
yMove = y;
int dx = xMove - xDown;//為負時:手指向左滑動;為正時:手指向右滑動。這與Android的屏幕坐標定義有關
int dy = yMove - yDown;//
//左滑
if (dx < 0 && Math.abs(dx) > mTouchSlop && Math.abs(dy) < mTouchSlop){
int newScrollX = Math.abs(dx);
if (mMoveWidth >= mHiddenWidth){//超過了,不能再移動了
newScrollX = 0;
} else if (mMoveWidth + newScrollX > mHiddenWidth){//這次要超了,
newScrollX = mHiddenWidth - mMoveWidth;
}
//左滑,每次滑動手指移動的距離
scrollLeft(mCurItemLayout, newScrollX);
//對移動的距離疊加
mMoveWidth = mMoveWidth + newScrollX;
}else if (dx > 0){//右滑
//執行右滑,這里沒有做跟隨,瞬間恢復
scrollRight(mCurItemLayout, 0 - mMoveWidth);
mMoveWidth = 0;
}
break;
case MotionEvent.ACTION_UP://手抬起時
int scrollX = mCurItemLayout.getScrollX();
if (mHiddenWidth > mMoveWidth) {
int toX = (mHiddenWidth - mMoveWidth);
if (scrollX > mHiddenWidth / 2) {//超過一半長度時松開,則自動滑到左側
scrollLeft(mCurItemLayout, toX);
mMoveWidth = mHiddenWidth;
} else {//不到一半時松開,則恢復原狀
scrollRight(mCurItemLayout, 0 - mMoveWidth);
mMoveWidth = 0;
}
}
mLastItemLayout = mCurItemLayout;
break;
}
return super.onTouchEvent(e);
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
Log.e(TAG, "computeScroll getCurrX ->" + mScroller.getCurrX());
mCurItemLayout.scrollBy(mScroller.getCurrX(), 0);
invalidate();
}
}
/**
* 向左滑動
*/
private void scrollLeft(View item, int scorllX){
Log.e(TAG, " scroll left -> " + scorllX);
item.scrollBy(scorllX, 0);
}
/**
* 向右滑動
*/
private void scrollRight(View item, int scorllX){
Log.e(TAG, " scroll right -> " + scorllX);
item.scrollBy(scorllX, 0);
}
public interface OnRightClickListener{
void onRightClick(int position, String id);
}
}
這樣我們就實現了給RecyclerView添加左滑刪除了 ,這是GitHub下載鏈接 See You Next Time !
