Android 项目需求:已经整好的列表ListView无侵入的加入右滑删除控件(自定义右滑控件操作)

已经整好了listView,后续需要加入右滑删除,在网上查了一堆资料,最终整理了一个无侵入性的

 

1.建立SwipeItemLayout  (作为子项item的最外层布局)

import android.content.Context;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.animation.Interpolator;
import android.widget.Scroller;



public class SwipeItemLayout extends ViewGroup {
    enum Mode{
        RESET,DRAG,FLING,TAP
    }

    private Mode mTouchMode;

    private ViewGroup mMainView;
    private ViewGroup mSideView;

    private ScrollRunnable mScrollRunnable;
    private int mScrollOffset;
    private int mMaxScrollOffset;

    private boolean mInLayout;
    private boolean mIsLaidOut;

    public SwipeItemLayout(Context context) {
        this(context,null);
    }

    public SwipeItemLayout(Context context, AttributeSet attrs) {
        super(context, attrs);

        mTouchMode = Mode.RESET;
        mScrollOffset = 0;

        mScrollRunnable = new ScrollRunnable(context);
    }

    public boolean isOpen(){
        return mScrollOffset !=0;
    }

    Mode getTouchMode(){
        return mTouchMode;
    }

    void setTouchMode(Mode mode){
        switch (mTouchMode){
            case FLING:
                mScrollRunnable.abort();
                break;
            case RESET:
                break;
        }

        mTouchMode = mode;
    }

    public void open(){
        if(mScrollOffset!=-mMaxScrollOffset){
            //正在open,不需要处理
            if(mTouchMode== Mode.FLING && mScrollRunnable.isScrollToLeft())
                return;

            //当前正在向右滑,abort
            if(mTouchMode== Mode.FLING /*&& !mScrollRunnable.mScrollToLeft*/)
                mScrollRunnable.abort();

            mScrollRunnable.startScroll(mScrollOffset,-mMaxScrollOffset);
        }
    }

    public void close(){
        if(mScrollOffset!=0){
            //正在close,不需要处理
            if(mTouchMode== Mode.FLING && !mScrollRunnable.isScrollToLeft())
                return;

            //当前正向左滑,abort
            if(mTouchMode== Mode.FLING /*&& mScrollRunnable.mScrollToLeft*/)
                mScrollRunnable.abort();

            mScrollRunnable.startScroll(mScrollOffset,0);
        }
    }

    void fling(int xVel){
        mScrollRunnable.startFling(mScrollOffset,xVel);
    }

    void revise(){
        if(mScrollOffset<-mMaxScrollOffset/2)
            open();
        else
            close();
    }

    boolean trackMotionScroll(int deltaX){
        if(deltaX==0)
            return false;

        boolean over = false;
        int newLeft = mScrollOffset+deltaX;
        if((deltaX>0 && newLeft>0) || (deltaX<0 && newLeft<-mMaxScrollOffset)){
            over = true;
            newLeft = Math.min(newLeft,0);
            newLeft = Math.max(newLeft,-mMaxScrollOffset);
        }

        offsetChildrenLeftAndRight(newLeft-mScrollOffset);
        mScrollOffset = newLeft;
        return over;
    }

    private boolean ensureChildren(){
        int childCount = getChildCount();

        if(childCount!=2)
            return false;

        View childView = getChildAt(0);
        if(!(childView instanceof ViewGroup))
            return false;
        mMainView = (ViewGroup) childView;

        childView = getChildAt(1);
        if(!(childView instanceof ViewGroup))
            return false;
        mSideView = (ViewGroup) childView;
        return true;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if(!ensureChildren())
            throw new RuntimeException("SwipeItemLayout的子视图不符合规定");

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        MarginLayoutParams lp = null;
        int horizontalMargin,verticalMargin;
        int horizontalPadding = getPaddingLeft()+getPaddingRight();
        int verticalPadding = getPaddingTop()+getPaddingBottom();

        lp = (MarginLayoutParams) mMainView.getLayoutParams();
        horizontalMargin = lp.leftMargin+lp.rightMargin;
        verticalMargin = lp.topMargin+lp.bottomMargin;
        measureChildWithMargins(mMainView,
                widthMeasureSpec,horizontalMargin+horizontalPadding,
                heightMeasureSpec,verticalMargin+verticalPadding);

        if(widthMode== MeasureSpec.AT_MOST)
            widthSize = Math.min(widthSize,mMainView.getMeasuredWidth()+horizontalMargin+horizontalPadding);
        else if(widthMode== MeasureSpec.UNSPECIFIED)
            widthSize = mMainView.getMeasuredWidth()+horizontalMargin+horizontalPadding;

        if(heightMode== MeasureSpec.AT_MOST)
            heightSize = Math.min(heightSize,mMainView.getMeasuredHeight()+verticalMargin+verticalPadding);
        else if(heightMode== MeasureSpec.UNSPECIFIED)
            heightSize = mMainView.getMeasuredHeight()+verticalMargin+verticalPadding;

        setMeasuredDimension(widthSize,heightSize);

        //side layout大小为自身实际大小
        lp = (MarginLayoutParams) mSideView.getLayoutParams();
        verticalMargin = lp.topMargin+lp.bottomMargin;
        mSideView.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
                MeasureSpec.makeMeasureSpec(getMeasuredHeight()-verticalMargin-verticalPadding, MeasureSpec.EXACTLY));
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if(!ensureChildren())
            throw new RuntimeException("SwipeItemLayout的子视图不符合规定");

        mInLayout = true;

        int pl = getPaddingLeft();
        int pt = getPaddingTop();
        int pr = getPaddingRight();
        int pb = getPaddingBottom();

        MarginLayoutParams mainLp = (MarginLayoutParams) mMainView.getLayoutParams();
        MarginLayoutParams sideParams = (MarginLayoutParams) mSideView.getLayoutParams();

        int childLeft = pl+mainLp.leftMargin;
        int childTop = pt+mainLp.topMargin;
        int childRight = getWidth()-(pr+mainLp.rightMargin);
        int childBottom = getHeight()-(mainLp.bottomMargin+pb);
        mMainView.layout(childLeft,childTop,childRight,childBottom);

        childLeft = childRight+sideParams.leftMargin;
        childTop = pt+sideParams.topMargin;
        childRight = childLeft+sideParams.leftMargin+sideParams.rightMargin+mSideView.getMeasuredWidth();
        childBottom = getHeight()-(sideParams.bottomMargin+pb);
        mSideView.layout(childLeft,childTop,childRight,childBottom);

        mMaxScrollOffset = mSideView.getWidth()+sideParams.leftMargin+sideParams.rightMargin;
        mScrollOffset = 0;//mScrollOffset<-mMaxScrollOffset/2 ? -mMaxScrollOffset:0;

        //offsetChildrenLeftAndRight(mScrollOffset);
        mInLayout = false;
        mIsLaidOut = true;
    }

    void offsetChildrenLeftAndRight(int delta){
        ViewCompat.offsetLeftAndRight(mMainView,delta);
        ViewCompat.offsetLeftAndRight(mSideView,delta);
    }

    @Override
    public void requestLayout() {
        if (!mInLayout) {
            super.requestLayout();
        }
    }

    @Override
    protected LayoutParams generateDefaultLayoutParams() {
        return new MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
    }

    @Override
    protected LayoutParams generateLayoutParams(LayoutParams p) {
        return p instanceof MarginLayoutParams ? p : new MarginLayoutParams(p);
    }

    @Override
    protected boolean checkLayoutParams(LayoutParams p) {
        return p instanceof MarginLayoutParams && super.checkLayoutParams(p);
    }

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(getContext(), attrs);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();

        if(mScrollOffset!=0 && mIsLaidOut){
            offsetChildrenLeftAndRight(-mScrollOffset);
            mScrollOffset = 0;
        }else
            mScrollOffset = 0;
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();

        if(mScrollOffset!=0 && mIsLaidOut){
            offsetChildrenLeftAndRight(-mScrollOffset);
            mScrollOffset = 0;
        }else
            mScrollOffset = 0;
        removeCallbacks(mScrollRunnable);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        final int action = ev.getActionMasked();
        //click main view,但是它处于open状态,所以,不需要点击效果,直接拦截不调用click listener
        switch (action) {
            case MotionEvent.ACTION_DOWN: {
                final int x = (int) ev.getX();
                final int y = (int) ev.getY();
                View pointView = findTopChildUnder(this,x,y);
                if(pointView!=null && pointView==mMainView && mScrollOffset !=0)
                    return true;
                break;
            }

            case MotionEvent.ACTION_MOVE:
            case MotionEvent.ACTION_CANCEL:
                break;

            case MotionEvent.ACTION_UP:{
                final int x = (int) ev.getX();
                final int y = (int) ev.getY();
                View pointView = findTopChildUnder(this,x,y);
                if(pointView!=null && pointView==mMainView && mTouchMode== Mode.TAP && mScrollOffset !=0)
                    return true;
                break;
            }
        }

        return false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        final int action = ev.getActionMasked();
        //click main view,但是它处于open状态,所以,不需要点击效果,直接拦截不调用click listener
        switch (action) {
            case MotionEvent.ACTION_DOWN: {
                final int x = (int) ev.getX();
                final int y = (int) ev.getY();
                View pointView = findTopChildUnder(this,x,y);
                if(pointView!=null && pointView==mMainView && mScrollOffset !=0)
                    return true;
                break;
            }

            case MotionEvent.ACTION_MOVE:
            case MotionEvent.ACTION_CANCEL:
                break;

            case MotionEvent.ACTION_UP:{
                final int x = (int) ev.getX();
                final int y = (int) ev.getY();
                View pointView = findTopChildUnder(this,x,y);
                if(pointView!=null && pointView==mMainView && mTouchMode== Mode.TAP && mScrollOffset !=0) {
                    close();
                    return true;
                }
                break;
            }
        }

        return false;
    }

    @Override
    protected void onVisibilityChanged(View changedView, int visibility) {
        super.onVisibilityChanged(changedView, visibility);
        if(getVisibility()!= View.VISIBLE){
            mScrollOffset = 0;
            invalidate();
        }
    }

    private static final Interpolator sInterpolator = new Interpolator() {
        @Override
        public float getInterpolation(float t) {
            t -= 1.0f;
            return t * t * t * t * t + 1.0f;
        }
    };

    class ScrollRunnable implements Runnable {
        private static final int FLING_DURATION = 200;
        private Scroller mScroller;
        private boolean mAbort;
        private int mMinVelocity;
        private boolean mScrollToLeft;

        ScrollRunnable(Context context){
            mScroller = new Scroller(context,sInterpolator);
            mAbort = false;
            mScrollToLeft = false;

            ViewConfiguration configuration = ViewConfiguration.get(context);
            mMinVelocity = configuration.getScaledMinimumFlingVelocity();
        }

        void startScroll(int startX,int endX){
            if(startX!=endX){
                Log.e("scroll - startX - endX",""+startX+" "+endX);
                setTouchMode(Mode.FLING);
                mAbort = false;
                mScrollToLeft = endX<startX;
                mScroller.startScroll(startX,0,endX-startX,0, 400);
                ViewCompat.postOnAnimation(SwipeItemLayout.this,this);
            }
        }

        void startFling(int startX,int xVel){
            Log.e("fling - startX",""+startX);

            if(xVel>mMinVelocity && startX!=0) {
                startScroll(startX, 0);
                return;
            }

            if(xVel<-mMinVelocity && startX!=-mMaxScrollOffset) {
                startScroll(startX, -mMaxScrollOffset);
                return;
            }

            startScroll(startX,startX>-mMaxScrollOffset/2 ? 0:-mMaxScrollOffset);
        }

        void abort(){
            if(!mAbort){
                mAbort = true;
                if(!mScroller.isFinished()){
                    mScroller.abortAnimation();
                    removeCallbacks(this);
                }
            }
        }

        //是否正在滑动需要另外判断
        boolean isScrollToLeft(){
            return mScrollToLeft;
        }

        @Override
        public void run() {
            Log.e("abort", Boolean.toString(mAbort));
            if(!mAbort){
                boolean more = mScroller.computeScrollOffset();
                int curX = mScroller.getCurrX();
                Log.e("curX",""+curX);

                boolean atEdge = trackMotionScroll(curX-mScrollOffset);
                if(more && !atEdge) {
                    ViewCompat.postOnAnimation(SwipeItemLayout.this, this);
                    return;
                }

                if(atEdge){
                    removeCallbacks(this);
                    if(!mScroller.isFinished())
                        mScroller.abortAnimation();
                    setTouchMode(Mode.RESET);
                }

                if(!more){
                    setTouchMode(Mode.RESET);
                    //绝对不会出现这种意外的!!!可以注释掉
                    if(mScrollOffset!=0){
                        if(Math.abs(mScrollOffset)>mMaxScrollOffset/2)
                            mScrollOffset = -mMaxScrollOffset;
                        else
                            mScrollOffset = 0;
                        ViewCompat.postOnAnimation(SwipeItemLayout.this,this);
                    }
                }
            }
        }
    }

    static View findTopChildUnder(ViewGroup parent, int x, int y) {
        final int childCount = parent.getChildCount();
        for (int i = childCount - 1; i >= 0; i--) {
            final View child = parent.getChildAt(i);
            if (x >= child.getLeft() && x < child.getRight()
                    && y >= child.getTop() && y < child.getBottom()) {
                return child;
            }
        }
        return null;
    }

}

2.建立SwipeListView (替换listView)



import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.ListView;
import com.huoduoduo.shipmerchant.module.main.others.SwipeItemLayout.Mode;


public class SwipeListView extends ListView {
    private SwipeItemLayout mCaptureItem;
    private float mLastMotionX;
    private float mLastMotionY;
    private VelocityTracker mVelocityTracker;

    private int mActivePointerId;

    private int mTouchSlop;
    private int mMaximumVelocity;

    private boolean mDragHandleBySuper;
    private boolean mDragHandleByThis;
    //如果item open,此时点击其它地方就close item,并且完全不处理后续的所以消息(即此时滑动不起作用了)。
    private boolean mIsCancelEvent;

    public SwipeListView(Context context) {
        this(context,null);
    }

    public SwipeListView(Context context, AttributeSet attrs) {
        super(context, attrs);

        ViewConfiguration configuration = ViewConfiguration.get(context);
        mTouchSlop = configuration.getScaledTouchSlop();
        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
        mActivePointerId = -1;
        mDragHandleBySuper = false;
        mDragHandleByThis = false;
        mIsCancelEvent = false;
    }

    @Override
    public boolean canScrollVertically(int direction) {
        return mDragHandleByThis
                || (mCaptureItem!=null && mCaptureItem.isOpen())
                || mIsCancelEvent
                ||super.canScrollVertically(direction);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        final int action = ev.getActionMasked();

        if(mIsCancelEvent && action!= MotionEvent.ACTION_UP && action!= MotionEvent.ACTION_CANCEL)
            return true;
        else if(mIsCancelEvent){
            cancel();
            return true;
        }

        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        }
        mVelocityTracker.addMovement(ev);

        switch (action){
            case MotionEvent.ACTION_DOWN:{
                mIsCancelEvent = false;
                mActivePointerId = ev.getPointerId(0);
                final float x = ev.getX(0);
                final float y = ev.getY(0);
                mLastMotionX = x;
                mLastMotionY = y;

                boolean pointOther = false;
                SwipeItemLayout pointItem = null;
                //首先知道ev针对的是哪个item
                View pointView = SwipeItemLayout.findTopChildUnder(this,(int)x,(int)y);
                if(pointView==null || !(pointView instanceof SwipeItemLayout))
                    pointOther = true;//可能是head view、bottom view或者其它类型的item
                else
                    pointItem = (SwipeItemLayout) pointView;

                //此时的pointOther=true,意味着点击的view为空或者点击的不是item
                //还没有把点击的是item但是不是capture item给过滤出来
                if(!pointOther && (mCaptureItem==null || mCaptureItem!=pointItem))
                    pointOther = true;

                //点击的是capture item
                if(!pointOther){
                    Mode touchMode = mCaptureItem.getTouchMode();

                    //如果它在fling,就转为drag
                    //需要拦截,并且requestDisallowInterceptTouchEvent
                    boolean disallowIntercept = false;
                    if(touchMode== Mode.FLING){
                        mCaptureItem.setTouchMode(Mode.DRAG);
                        disallowIntercept = true;
                        mDragHandleByThis = true;
                    }else {//如果是expand的,就不允许parent拦截
                        mCaptureItem.setTouchMode(Mode.TAP);
                        if(mCaptureItem.isOpen())
                            disallowIntercept = true;
                    }

                    if(disallowIntercept){
                        final ViewParent parent = getParent();
                        if (parent!= null)
                            parent.requestDisallowInterceptTouchEvent(true);
                    }
                }else{//capture item为null或者与point item不一样
                    //直接将其close掉
                    if(mCaptureItem!=null && mCaptureItem.isOpen()) {
                        mCaptureItem.close();
                        mIsCancelEvent = true;
                        return true;
                    }

                    if(pointItem!=null) {
                        mCaptureItem = pointItem;
                        mCaptureItem.setTouchMode(Mode.TAP);
                    }
                }

                //如果parent处于fling状态,此时,parent就会转为drag。此时,应该将后续move都交给parent处理
                if(!mDragHandleByThis)
                    mDragHandleBySuper = super.onInterceptTouchEvent(ev);
                return mDragHandleByThis || mDragHandleBySuper;
            }

            case MotionEvent.ACTION_POINTER_UP: {
                final int actionIndex = ev.getActionIndex();
                final int pointerId = ev.getPointerId(actionIndex);
                if (pointerId == mActivePointerId) {
                    final int newIndex = actionIndex == 0 ? 1 : 0;
                    mActivePointerId = ev.getPointerId(newIndex);

                    mLastMotionX = ev.getX(newIndex);
                    mLastMotionY = ev.getY(newIndex);
                }

                return super.onInterceptTouchEvent(ev);
            }

            //down时,已经将capture item定下来了。所以,后面可以安心考虑event处理
            case MotionEvent.ACTION_MOVE: {
                //在down时,就被认定为parent的drag,所以,直接交给parent处理即可
                if(mDragHandleBySuper) {
                    if(mCaptureItem!=null)
                        mCaptureItem.close();
                    return super.onInterceptTouchEvent(ev);
                }

                final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
                if (activePointerIndex == -1)
                    break;

                final int x = (int) (ev.getX(activePointerIndex)+.5f);
                final int y = (int) ((int) ev.getY(activePointerIndex)+.5f);

                int deltaX = (int) (x - mLastMotionX);
                int deltaY = (int)(y-mLastMotionY);
                final int xDiff = Math.abs(deltaX);
                final int yDiff = Math.abs(deltaY);

                if(mCaptureItem!=null){
                    Mode touchMode = mCaptureItem.getTouchMode();

                    if(touchMode== Mode.TAP ){
                        //如果capture item是open的,下拉有两种处理方式:
                        //  1、下拉后,直接close item
                        //  2、只要是open的,就拦截所有它的消息,这样如果点击open的,就只能滑动该capture item
                        //网易邮箱,在open的情况下,下拉直接close
                        //QQ,在open的情况下,下拉也是close。但是,做的不够好,没有达到该效果。
                        if(xDiff>mTouchSlop && xDiff>yDiff){
                            mDragHandleByThis = true;
                            mCaptureItem.setTouchMode(Mode.DRAG);
                            final ViewParent parent = getParent();
                            parent.requestDisallowInterceptTouchEvent(true);

                            deltaX = deltaX>0 ? deltaX-mTouchSlop:deltaX+mTouchSlop;
                        }else{
                            //表明不是水平滑动,即不判定为SwipeItemLayout的滑动
                            //但是,可能是下拉刷新SwipeRefreshLayout或者RecyclerView的滑动
                            //一般的下拉判定,都是yDiff>mTouchSlop,所以,此处这么写不会出问题
                            //这里这么做以后,如果判定为下拉,就直接close
                            mDragHandleBySuper = super.onInterceptTouchEvent(ev);
                        }
                    }

                    touchMode = mCaptureItem.getTouchMode();
                    if(touchMode== Mode.DRAG){
                        mLastMotionX = x;
                        mLastMotionY = y;

                        //对capture item进行拖拽
                        mCaptureItem.trackMotionScroll(deltaX);
                    }
                }else
                    mDragHandleBySuper = super.onInterceptTouchEvent(ev);

                if(mDragHandleBySuper && mCaptureItem!=null)
                    mCaptureItem.close();
                return mDragHandleByThis || mDragHandleBySuper;
            }

            case MotionEvent.ACTION_UP:
                boolean ret = false;
                if(mDragHandleByThis && mCaptureItem!=null/**起始一定不为null*/){
                    Mode touchMode = mCaptureItem.getTouchMode();
                    if(touchMode== Mode.DRAG){
                        final VelocityTracker velocityTracker = mVelocityTracker;
                        velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
                        int xVel = (int) velocityTracker.getXVelocity(mActivePointerId);
                        mCaptureItem.fling(xVel);
                        ret = true;
                    }
                }else
                    ret = super.onInterceptTouchEvent(ev);

                cancel();
                return ret;

            case MotionEvent.ACTION_CANCEL:
                if(mCaptureItem!=null)
                    mCaptureItem.revise();
                super.onInterceptTouchEvent(ev);
                cancel();
                break;
        }

        return false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        final int action = ev.getActionMasked();
        final int actionIndex = ev.getActionIndex();

        if(mIsCancelEvent && action!= MotionEvent.ACTION_UP && action!= MotionEvent.ACTION_CANCEL)
            return true;
        else if(mIsCancelEvent){
            cancel();
            return true;
        }

        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        }
        mVelocityTracker.addMovement(ev);

        switch (action){
            case MotionEvent.ACTION_DOWN:
                //如果调用super.onTouchEvent(ev);必然导致super.onInterceptTouchEvent(ev)无法返回true,所以不能调用它,直接返回true
                //但是super.onTouchEvent(ev)就无法处理DOWN消息,从而无法处理item click。所以,只能通过click listener的方式来处理点击消息!!!
                //不调用的问题在于会导致没有item click效果、没有flywheel效果
                 return super.onTouchEvent(ev);

            case MotionEvent.ACTION_POINTER_DOWN:
                mActivePointerId = ev.getPointerId(actionIndex);

                mLastMotionX = ev.getX(actionIndex);
                mLastMotionY = ev.getY(actionIndex);
                return super.onTouchEvent(ev);

            case MotionEvent.ACTION_POINTER_UP:
                final int pointerId = ev.getPointerId(actionIndex);
                if(pointerId==mActivePointerId){
                    final int newIndex = actionIndex == 0 ? 1 : 0;
                    mActivePointerId = ev.getPointerId(newIndex);

                    mLastMotionX = ev.getX(newIndex);
                    mLastMotionY = ev.getY(newIndex);
                }
                return super.onTouchEvent(ev);

            case MotionEvent.ACTION_MOVE: {
                //在down时,就被认定为parent的drag,所以,直接交给parent处理即可
                if(mDragHandleBySuper) {
                    if(mCaptureItem!=null)
                        mCaptureItem.close();
                    return super.onTouchEvent(ev);
                }

                final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
                if (activePointerIndex == -1)
                    break;

                final int x = (int) (ev.getX(activePointerIndex)+.5f);
                final int y = (int) ((int) ev.getY(activePointerIndex)+.5f);

                int deltaX = (int) (x - mLastMotionX);
                int deltaY = (int)(y-mLastMotionY);
                final int xDiff = Math.abs(deltaX);
                final int yDiff = Math.abs(deltaY);

                if(mCaptureItem!=null){
                    Mode touchMode = mCaptureItem.getTouchMode();

                    if(touchMode== Mode.TAP ){
                        //如果capture item是open的,下拉有两种处理方式:
                        //  1、下拉后,直接close item
                        //  2、只要是open的,就拦截所有它的消息,这样如果点击open的,就只能滑动该capture item
                        //网易邮箱,在open的情况下,下拉直接close
                        //QQ,在open的情况下,下拉也是close。但是,做的不够好,没有达到该效果。
                        if(xDiff>mTouchSlop && xDiff>yDiff){
                            mDragHandleByThis = true;
                            mCaptureItem.setTouchMode(Mode.DRAG);
                            final ViewParent parent = getParent();
                            parent.requestDisallowInterceptTouchEvent(true);

                            deltaX = deltaX>0 ? deltaX-mTouchSlop:deltaX+mTouchSlop;
                        }else if(yDiff>mTouchSlop){
                            //表明不是水平滑动,即不判定为SwipeItemLayout的滑动
                            //但是,可能是下拉刷新SwipeRefreshLayout或者RecyclerView的滑动
                            //一般的下拉判定,都是yDiff>mTouchSlop,所以,此处这么写不会出问题
                            //这里这么做以后,如果判定为下拉,就直接close
                            //不能调用onTouchEvent(),因为它一定返回true
                            mDragHandleBySuper = true;//super.onInterceptTouchEvent(ev);
                            super.onTouchEvent(ev);
                        }
                    }

                    touchMode = mCaptureItem.getTouchMode();
                    if(touchMode== SwipeItemLayout.Mode.DRAG){
                        mLastMotionX = x;
                        mLastMotionY = y;

                        //对capture item进行拖拽
                        mCaptureItem.trackMotionScroll(deltaX);
                    }
                }else
                    mDragHandleBySuper = super.onTouchEvent(ev);

                if(mDragHandleBySuper && mCaptureItem!=null)
                    mCaptureItem.close();
                return true;
            }

            case MotionEvent.ACTION_UP:
                if(mDragHandleByThis && mCaptureItem!=null/**起始一定不为null*/){
                    Mode touchMode = mCaptureItem.getTouchMode();
                    if(touchMode== Mode.DRAG){
                        final VelocityTracker velocityTracker = mVelocityTracker;
                        velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
                        int xVel = (int) velocityTracker.getXVelocity(mActivePointerId);
                        mCaptureItem.fling(xVel);
                    }
                }else
                    super.onTouchEvent(ev);

                cancel();
                return true;

            case MotionEvent.ACTION_CANCEL:
                if(mCaptureItem!=null)
                    mCaptureItem.revise();
                super.onTouchEvent(ev);
                cancel();
                return true;
        }
        return true;
    }

    void cancel(){
        mDragHandleBySuper = false;
        mDragHandleByThis = false;
        mIsCancelEvent = false;
        mActivePointerId = -1;
        if(mVelocityTracker!=null){
            mVelocityTracker.recycle();
            mVelocityTracker = null;
        }
    }

    public void closeAllItems(ViewGroup parent){
        if(mCaptureItem!=null && mCaptureItem.isOpen())
            mCaptureItem.close();
    }

}

3.把原来item的布局最外层替换成新加入的SwipeItemLayout

<?xml version="1.0" encoding="utf-8"?>

<SwipeItemLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    >

    <LinearLayout
        android:id="@+id/ll_driver"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp_90"
        android:layout_marginTop="@dimen/dp_10"
        android:background="@color/white"
        android:gravity="center"
        android:orientation="horizontal"
        android:paddingRight="@dimen/dp_16">

          // 略略略略略略略略略略略略略略
    

    </LinearLayout>
//这里是新加入的右滑出的自定义的布局 demo只写了一个删除按钮 
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_marginTop="@dimen/dp_10">

        <Button
            android:id="@+id/btn_delete"
            android:layout_width="100dp"
            android:layout_height="match_parent"
            android:background="@drawable/btn_delete"
            android:text="删除"
            android:textColor="#ffffff"
            android:textSize="16sp" />

    </LinearLayout>
</SwipeItemLayout>


4.把原来的listView改成SwipeListView

 //支持在SmartRefreshLayout里 原来的功能不变
<com.scwang.smartrefresh.layout.SmartRefreshLayout
        android:id="@+id/refreshLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:srlEnableScrollContentWhenLoaded="true"
        android:visibility="gone"
        android:layout_above="@+id/btn_confirm"
        android:layout_below="@+id/ll_toolbar"
        app:srlEnableFooterFollowWhenLoadFinished="true">

//只是把这的listView换了SwipeListView
        <SwipeListView
            android:id="@+id/listView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#f4f4f4"
            android:overScrollMode="never"
            android:dividerHeight="@dimen/line_height"
            android:divider="@color/color_e4e4e4"
            tools:listitem="@android:layout/simple_list_item_2" />

    </SmartRefreshLayout>

5.原来listview的adapter不变 只需加入自定义控件的事件就好了

     RelativeLayout linearLayout = (RelativeLayout) holder.findViewById(R.id.ll_driver);
                linearLayout.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                       //原来的item点击事件
                        }
                    }
                });
                Button btnDelete = (Button) holder.findViewById(R.id.btn_delete);
                btnDelete.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        //自定义的删除事件
                        delete(driverId);
                        mAdapter.notifyDataSetInvalidated();
                    }
                });

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值