自定義RecyclerView 支持 橫向縱向,滑動刪除Item
項目源碼已經放上去:https://github.com/xufeifandj/SwipeRecyclerView
本項目直接 繼承于RecyclerView 本身就支持 橫向縱向的 列表。
具體代碼請看代碼。
package com.ferris.holeswipeview;import android.content.Context; import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; import android.view.WindowManager; import android.widget.AdapterView; import android.widget.Scroller; /** * http://blog.csdn.net/xufeifandj www.github.com/xufeifandj * * @ferris 459821731@qq.com * */ public class CusomSwipeView extends RecyclerView { private Orientation orientation = Orientation.HORIZONTAL; /** * 當前滑動的ListView position */ private int slidePosition; /** * 手指按下X的坐標 */ private int downY; /** * 手指按下Y的坐標 */ private int downX; /** * 屏幕寬度 */ private int screenWidth; /** * ListView的item */ private View itemView; /** * 滑動類 */ private Scroller scroller; private static final int SNAP_VELOCITY = 600; /** * 速度追蹤對象 */ private VelocityTracker velocityTracker; /** * 是否響應滑動,默認為不響應 */ private boolean isSlide = false; /** * 認為是用戶滑動的最小距離 */ private int mTouchSlop; /** * 移除item后的回調接口 */ private RemoveListener mRemoveListener; /** * 用來指示item滑出屏幕的方向,向左或者向右,用一個枚舉值來標記 */ private RemoveDirection removeDirection; // 滑動刪除方向的枚舉值 public enum RemoveDirection { RIGHT, LEFT; } public CusomSwipeView(Context context) { super(context); // TODO Auto-generated constructor stub init(context); } public CusomSwipeView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub init(context); } public CusomSwipeView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // TODO Auto-generated constructor stub init(context); } public void init(Context context) { if (orientation == Orientation.VERTICAL) { screenWidth = ((WindowManager) context .getSystemService(Context.WINDOW_SERVICE)) .getDefaultDisplay().getWidth(); } else { screenWidth = ((WindowManager) context .getSystemService(Context.WINDOW_SERVICE)) .getDefaultDisplay().getHeight(); } scroller = new Scroller(context); mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); } /** * 設置滑動刪除的回調接口 * * @param removeListener */ public void setRemoveListener(RemoveListener removeListener) { this.mRemoveListener = removeListener; } /** * 分發事件,主要做的是判斷點擊的是那個item, 以及通過postDelayed來設置響應左右滑動事件 */ @Override public boolean dispatchTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { addVelocityTracker(event); // 假如scroller滾動還沒有結束,我們直接返回 if (!scroller.isFinished()) { return super.dispatchTouchEvent(event); } downX = (int) event.getX(); downY = (int) event.getY(); itemView = findChildViewUnder(downX, downY); if (itemView == null) { return super.dispatchTouchEvent(event); } slidePosition = getChildPosition(itemView); // 無效的position, 不做任何處理 if (slidePosition == AdapterView.INVALID_POSITION) { return super.dispatchTouchEvent(event); } break; } case MotionEvent.ACTION_MOVE: { if (orientation == Orientation.VERTICAL) {// 如果 // 左右滑動的距離大于最大的滑動距離,并且沒有上下滑動,就代表 // 右滑刪除或者左滑刪除 if (Math.abs(getScrollVelocity()) > SNAP_VELOCITY || (Math.abs(event.getX() - downX) > mTouchSlop && Math .abs(event.getY() - downY) < mTouchSlop)) { isSlide = true; } } else { // 如果 上下滑動的距離大于最大的滑動距離,并且沒有左右滑動,就代表上滑刪除或者下滑刪除 if (Math.abs(getScrollVelocity()) > SNAP_VELOCITY || (Math.abs(event.getY() - downY) > mTouchSlop && Math .abs(event.getX() - downX) < mTouchSlop)) { isSlide = true; } } break; } case MotionEvent.ACTION_UP: recycleVelocityTracker(); break; } return super.dispatchTouchEvent(event); } /** * 往右滑動,getScrollX()返回的是左邊緣的距離,就是以View左邊緣為原點到開始滑動的距離,所以向右邊滑動為負值 */ private void scrollRight() { if (orientation == Orientation.VERTICAL) {// 往右滑動 removeDirection = RemoveDirection.RIGHT; final int delta = (screenWidth + itemView.getScrollX()); // 調用startScroll方法來設置一些滾動的參數,我們在computeScroll()方法中調用scrollTo來滾動item scroller.startScroll(itemView.getScrollX(), 0, -delta, 0, Math.abs(delta)); postInvalidate(); // 刷新itemView } else {// 往上滑動 removeDirection = RemoveDirection.RIGHT; final int delta = (screenWidth + itemView.getScrollY()); // 調用startScroll方法來設置一些滾動的參數,我們在computeScroll()方法中調用scrollTo來滾動item scroller.startScroll(0, itemView.getScrollY(), -delta, 0, Math.abs(delta)); postInvalidate(); // 刷新itemView } } /** * 向左滑動,根據上面我們知道向左滑動為正值 */ private void scrollLeft() { if (orientation == Orientation.VERTICAL) {// 往左滑動 removeDirection = RemoveDirection.LEFT; final int delta = (screenWidth - itemView.getScrollX()); // 調用startScroll方法來設置一些滾動的參數,我們在computeScroll()方法中調用scrollTo來滾動item scroller.startScroll(itemView.getScrollX(), 0, delta, 0, Math.abs(delta)); postInvalidate(); // 刷新itemView } else { removeDirection = RemoveDirection.LEFT; final int delta = (screenWidth - itemView.getScrollY()); // 調用startScroll方法來設置一些滾動的參數,我們在computeScroll()方法中調用scrollTo來滾動item scroller.startScroll(0, itemView.getScrollY(), delta, 0, Math.abs(delta)); postInvalidate(); // 刷新itemView } } /** * 根據手指滾動itemView的距離來判斷是滾動到開始位置還是向左或者向右滾動 */ private void scrollByDistanceX() { // 如果向左滾動的距離大于屏幕的二分之一,就讓其刪除 if (orientation == Orientation.VERTICAL) { if (itemView.getScrollX() >= screenWidth / 2) { scrollLeft(); } else if (itemView.getScrollX() <= -screenWidth / 2) { scrollRight(); } else { // 滾回到原始位置,為了偷下懶這里是直接調用scrollTo滾動 itemView.scrollTo(0, 0); } } else { if (itemView.getScrollY() >= screenWidth / 2) { scrollLeft(); } else if (itemView.getScrollY() <= -screenWidth / 2) { scrollRight(); } else { // 滾回到原始位置,為了偷下懶這里是直接調用scrollTo滾動 itemView.scrollTo(0, 0); } } } /** * 處理我們拖動ListView item的邏輯 */ @Override public boolean onTouchEvent(MotionEvent ev) { if (isSlide && slidePosition != AdapterView.INVALID_POSITION && itemView != null) { requestDisallowInterceptTouchEvent(true); addVelocityTracker(ev); final int action = ev.getAction(); int x = (int) ev.getX(); int y = (int) ev.getY(); switch (action) { case MotionEvent.ACTION_DOWN: break; case MotionEvent.ACTION_MOVE: MotionEvent cancelEvent = MotionEvent.obtain(ev); cancelEvent .setAction(MotionEvent.ACTION_CANCEL | (ev.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT)); onTouchEvent(cancelEvent); if (orientation == Orientation.VERTICAL) { int deltaX = downX - x; downX = x; // 手指拖動itemView滾動, deltaX大于0向左滾動,小于0向右滾 itemView.scrollBy(deltaX, 0); } else { int deltaY = downY - y; downY = y; itemView.scrollBy(0, deltaY); } return true; // 拖動的時候ListView不滾動 case MotionEvent.ACTION_UP: int velocityX = getScrollVelocity(); if (velocityX > SNAP_VELOCITY) { scrollRight(); } else if (velocityX < -SNAP_VELOCITY) { scrollLeft(); } else { scrollByDistanceX(); } recycleVelocityTracker(); // 手指離開的時候就不響應左右滾動 isSlide = false; break; } } // 否則直接交給ListView來處理onTouchEvent事件 return super.onTouchEvent(ev); } @Override public void computeScroll() { // 調用startScroll的時候scroller.computeScrollOffset()返回true, if (scroller.computeScrollOffset()) { // 讓ListView item根據當前的滾動偏移量進行滾動 itemView.scrollTo(scroller.getCurrX(), scroller.getCurrY()); postInvalidate(); // 滾動動畫結束的時候調用回調接口 if (scroller.isFinished()) { if (mRemoveListener == null) { throw new NullPointerException( "RemoveListener is null, we should called setRemoveListener()"); } itemView.scrollTo(0, 0); mRemoveListener.removeItem(removeDirection, slidePosition); } } } /** * 添加用戶的速度跟蹤器 * * @param event */ private void addVelocityTracker(MotionEvent event) { if (velocityTracker == null) { velocityTracker = VelocityTracker.obtain(); } velocityTracker.addMovement(event); } /** * 移除用戶速度跟蹤器 */ private void recycleVelocityTracker() { if (velocityTracker != null) { velocityTracker.recycle(); velocityTracker = null; } } /** * 獲取X方向的滑動速度,大于0向右滑動,反之向左 * * @return */ private int getScrollVelocity() { if (orientation == Orientation.VERTICAL) { velocityTracker.computeCurrentVelocity(1000); int velocity = (int) velocityTracker.getXVelocity(); return velocity; }else{ velocityTracker.computeCurrentVelocity(1000); int velocity = (int) velocityTracker.getYVelocity(); return velocity; } } /** * * 當ListView item滑出屏幕,回調這個接口 我們需要在回調方法removeItem()中移除該Item,然后刷新ListView * * */ public interface RemoveListener { public void removeItem(RemoveDirection direction, int position); } public static enum Orientation { HORIZONTAL(0), VERTICAL(1); private int value; private Orientation(int i) { value = i; } public int value() { return value; } public static Orientation valueOf(int i) { switch (i) { case 0: return HORIZONTAL; case 1: return VERTICAL; default: throw new RuntimeException("[0->HORIZONTAL, 1->VERTICAL]"); } } } } </pre><br />
本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!