本篇文章主要介绍如何侧滑删除条目的案例: 首先我们需要做一个自定义的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 = 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,则删除按钮隐藏
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)
/**
* 删除按钮回调
* @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文件代码:
activity的xml文件代码:
贴出完整代码的demo下载地址:http://download.csdn.net/download/today_work/10207552 最后如果测试有什么问题,请各位指出。
|