本篇文章主要介紹如何側滑刪除條目的案例:
首先我們需要做一個自定義的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
最後如果測試有什麼問題,請各位指出。