自定义RecyclerView 支持 横向纵向,滑动删除Item

jopen 9年前

项目源码已经放上去: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]");                    }                }            }        }  

来自:http://blog.csdn.net/xufeifandj/article/details/46618423