本篇文章主要介绍如何侧滑删除条目的案例:
首先我们需要做一个自定义的recyclerView
1,用到的东西有,onTouch事件,触屏事件跟踪VelocityTracker,滑动view.scrollTo和scrollBy,Scroller的使用。
整个过程主要是对MotionEvent的三种状态:
1,down
判定当前条目状态,如果完全打开则立即关闭返回,如果关闭状态,则根据getX()和getY()获取当前位置拿到当前item条目。
2,move
判断是否为横向滑动
判断移动的距离是否超过左边界和右边界。
3,up
判断速率超过1s内滑动100个像素。超过则关闭或完全打开(向左滑动速度为负数,右滑动为正数)
判定二:滑动的距离超过删除按钮一半长度,则完全滑出来,否则关闭。
话不多说上代码:
package com.hitv.recyclerview;
import android.content.Context;
import android.support.annotation.Nullable;
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.VelocityTracker;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.widget.LinearLayout;
import android.widget.Scroller;
import android.widget.TextView;
public class SwipeRecyclerview extends RecyclerView {
private Context mContext;
//上一次的触摸点
private int mLastX, mLastY;
//当前触摸的item的位置
private int mPosition;
//item对应的布局
private LinearLayout mItemLayout;
//删除按钮
private TextView mDelete;
//最大滑动距离(即删除按钮的宽度)
private int mMaxLength;
//item是在否跟随手指移动
private boolean isItemMoving;
//item是否开始自动滑动
private boolean isStartScroll;
//删除按钮状态 0:关闭 1:将要关闭 2:将要打开 3:打开
private int mDeleteBtnState;
private int scrollY = 0;
//检测手指在滑动过程中的速度
private VelocityTracker mVelocityTracker;
private Scroller mScroller;
private OnItemDeleteListener mListener;
private OnListItemClickListener mOnListItemClickListener;
private static final String TAG = "SwipeRecyclerview";
private float mDownY;
private float mDownX;
public SwipeRecyclerview(Context context) {
this(context, null);
}
public SwipeRecyclerview(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public SwipeRecyclerview(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mContext = context;
mScroller = new Scroller(context, new LinearInterpolator());
mVelocityTracker = VelocityTracker.obtain();
}
@Override
public boolean onTouchEvent(MotionEvent e) {
mVelocityTracker.addMovement(e);
int x = (int) e.getX();
int y = (int) e.getY();
Log.d(TAG, "onTouchEvent: mask"+e.getActionMasked());
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
mDownX = e.getX();
mDownY = e.getY();
if (mDeleteBtnState == 0) {
View view = findChildViewUnder(x, y);
Log.d(TAG, "onTouchEvent: "+view);
if (view == null) {
return false;
}
scrollY = getScrollYDistance();
EventAdapter.EventHolder viewHolder = (EventAdapter.EventHolder) getChildViewHolder(view);
mItemLayout = viewHolder.mLayout;
mPosition = viewHolder.getAdapterPosition();
mDelete = viewHolder.mTxtDelete;
mMaxLength = mDelete.getWidth();
mDelete.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mListener.onDeleteClick(mPosition);
mItemLayout.scrollTo(0, 0);
mDeleteBtnState = 0;
}
});
} else if (mDeleteBtnState == 3){
mScroller.startScroll(mItemLayout.getScrollX(), 0, -mMaxLength, 0, 200);
invalidate();
mDeleteBtnState = 0;
return false;
}else{
return false;
}
break;
case MotionEvent.ACTION_MOVE:
int dx = mLastX - x; //需要滑动的距离,每次滑动的距离
int dy = mLastY - y;
int scrollX = mItemLayout.getScrollX();//表示的是坐标原点-它的坐标位置
Log.d(TAG, "onTouchEvent: mLastX= "+mLastX+" ,x="+x+" ,mLastY="+mLastY+" ,y="+y+" ,scrollX="+scrollX+" ,daxiao="+(scrollX + dx));
if (Math.abs(dx) > Math.abs(dy)) {//左边界检测
isItemMoving = true;
if (scrollX + dx <= 0) {
mItemLayout.scrollTo(0, 0);
return true;
} else if (scrollX + dx >= mMaxLength) {//右边界检测
mItemLayout.scrollTo(mMaxLength, 0);
return true;
}
mItemLayout.scrollBy(dx, 0); //item跟随手指滑动
}
break;
case MotionEvent.ACTION_UP:
float upX = e.getX();
float upY = e.getY();
mVelocityTracker.computeCurrentVelocity(1000);//计算手指滑动的速度
float xVelocity = mVelocityTracker.getXVelocity();//水平方向速度(向左为负)
float yVelocity = mVelocityTracker.getYVelocity();//垂直方向速度
int deltaX = 0;
int upScrollX = mItemLayout.getScrollX();
if (Math.abs(xVelocity) > 100 && Math.abs(xVelocity) > Math.abs(yVelocity)) {
if (xVelocity <= -100) {//左滑速度大于100,则删除按钮显示
deltaX = mMaxLength - upScrollX;
mDeleteBtnState = 2;
} else if (xVelocity > 100) {//右滑速度大于100,则删除按钮隐藏
deltaX = -upScrollX;
mDeleteBtnState = 1;
}
} else {
if (upScrollX >= mMaxLength / 2) {//item的左滑动距离大于删除按钮宽度的一半,则则显示删除按钮
deltaX = mMaxLength - upScrollX;
mDeleteBtnState = 2;
} else if (upScrollX < mMaxLength / 2) {//否则隐藏
deltaX = -upScrollX;
mDeleteBtnState = 1;
}
}
//item自动滑动到指定位置
mScroller.startScroll(upScrollX, 0, deltaX, 0, 200);
isStartScroll = true;
invalidate();
float v = Math.abs(Math.abs(upX) - Math.abs(mDownX));
float v1 = Math.abs(Math.abs(upY) - Math.abs(mDownY));
Log.d(TAG, "onTouchEvent:v= "+upX+" "+mDownX+" "+v1);
mVelocityTracker.clear();
if (Math.abs(getScrollYDistance() - scrollY) <= 0 && !isItemMoving&&v1<=v) {
mOnListItemClickListener.onListItemClick(mPosition);
}
isItemMoving = false;
int scrollYDistance = getScrollYDistance();
Log.d(TAG, "onTouchEvent:ydistance "+scrollYDistance);
break;
}
Log.d(TAG, "onTouchEvent: "+x);
mLastX = x;
mLastY = y;//
return super.onTouchEvent(e);
}
@Override
public void computeScroll() {
Log.d(TAG, "computeScroll: ");
if (mScroller.computeScrollOffset()) {
mItemLayout.scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
invalidate();
} else if (isStartScroll) {
isStartScroll = false;
if (mDeleteBtnState == 1) {
mDeleteBtnState = 0;
}
if (mDeleteBtnState == 2) {
mDeleteBtnState = 3;
}
}
}
@Override
protected void onDetachedFromWindow() {
mVelocityTracker.recycle();
super.onDetachedFromWindow();
}
public void setOnItemDeleteListener(OnItemDeleteListener listener) {
mListener = listener;
}
public void setOnListItemClickListener(OnListItemClickListener listener) {
this.mOnListItemClickListener = listener;
}
/**
* 列表点击
*/
public interface OnListItemClickListener {
void onListItemClick(int position);
}
public interface OnItemDeleteListener {
/**
* 删除按钮回调
* @param position
*/
void onDeleteClick(int position);
}
public int getScrollYDistance() {
LinearLayoutManager layoutManager = (LinearLayoutManager) this.getLayoutManager();
int position = layoutManager.findFirstVisibleItemPosition();
View view = layoutManager.findViewByPosition(position);
int itemHeight = view.getHeight();
Log.d("TAG", "getScrollYDistance: "+position+" "+view.getTop()+" "+view.getLeft()+" "+view.getRight()+" "+view.getBottom()+" "+view.getPaddingBottom()+" "+view.getPaddingLeft());
return (position) * itemHeight - view.getTop();//view.getTop()表示的当前view相对于父控件的坐标有正负
}
}
条目的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="vertical">
<LinearLayout
android:id="@+id/layout_alarm_root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="vertical">
<TextView
android:id="@+id/txt_alarm_event"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="开会"
android:textColor="#600000"
android:textSize="21sp"/>
<ImageView
android:id="@+id/img_alarm_switch"
android:layout_width="40dp"
android:layout_height="22dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:src="@mipmap/ic_launcher"/>
</RelativeLayout>
<TextView
android:id="@+id/txt_alarm_delete"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginLeft="5dp"
android:layout_marginStart="5dp"
android:background="#88990000"
android:gravity="center"
android:text="删除"
android:textColor="#99ff0000"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_alignParentBottom="true"
android:layout_below="@+id/txt_alarm_day"
android:background="#33979797"/>
</LinearLayout>
activity的xml文件代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.hitv.recyclerview.MainActivity">
<com.hitv.recyclerview.SwipeRecyclerview
android:layout_weight="10"
android:id="@+id/sp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</com.hitv.recyclerview.SwipeRecyclerview>
</LinearLayout>
贴出完整代码的demo下载地址:http://download.csdn.net/download/today_work/10207552
最后如果测试有什么问题,请各位指出。