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 !