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 !