Android滑动删除控件

Android滑动删除控件

效果展示

代码实现

静态布局

自定义一个ViewGroup,继承至FrameLayout,覆写其中的几个关键方法,用于给其中的两个子view设置布局位置。


    private View contentView, deleteView;
    int contentViewHeight, contentViewWidth;
    int deleteViewHeight, deleteViewWidth;

    private void init() {
    }


    /**
     * 从xml中加载完布局,只知道有几个子view,并没有进行测量
     * 一般可以初始化子view的引用
     */
    @Override
    protected void onFinishInflate() {
    super.onFinishInflate();
    contentView = getChildAt(0);
    deleteView = getChildAt(1);
    }

    /**
     * 测量完子view后调用,在这里可以直接获取子view的高度
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    contentViewWidth = contentView.getMeasuredWidth();
    deleteViewHeight = deleteView.getMeasuredHeight();
    }


    /**
     * 放置子view到合适的位置
     */
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    super.onLayout(changed, left, top, right, bottom);
    contentView.layout(0, 0, contentViewWidth, contentViewHeight);
    deleteView.layout(contentViewWidth, 0, contentViewWidth + deleteViewWidth,  deleteViewHeight);
    }

处理滑动逻辑

利用ViewDragHelper类封装了对触摸位置、速度、距离的检测,以及Scroller.
需要我们制定什么时候滑动,以及滑动多少。
需要把ViewGroup中受到的触摸事件传给ViewDragHelper实例。

触摸事件传给ViewDragHelper实例


       @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return mViewDragHelper.shouldInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mViewDragHelper.processTouchEvent(event);

        //消费掉此触摸事件,不向上返回
        return true;
    }

在ViewDragHelper的回调函数中处理滑动逻辑。


    private ViewDragHelper mViewDragHelper;
    private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {

        /**
         * @return 返回true表示获得view的控制权
         */
        @Override
        public boolean tryCaptureView(View view, int i) {
            return view == contentView || view == deleteView;
        }

        @Override
        public void onViewCaptured(View capturedChild, int activePointerId) {
            super.onViewCaptured(capturedChild, activePointerId);
        }

        /**
         * 控制view在水平方向上实际滑动了多少
         * @param child 当前触摸的view
         * @param left view的左边座标,负数表示view的左边超出父view边界的长度
         * @param dx
         * @return 返回多少,代表想让child的left=多少
         */
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            Log.i(TAG, "clampViewPositionHorizontal-->" + "left=" + left);
            if (child == contentView) {
                if (left > 0) left = 0;
                if (left < -deleteViewWidth) left = -deleteViewWidth;
            } else if (child == deleteView) {
                //使deleteVie不会超出指定的边界
                if (left < contentViewWidth - deleteViewWidth) {
                    left = contentViewWidth - deleteViewWidth;
                }
            }
            return left;
        }

        /**
         * 水平方向拖拽的范围
         */
        @Override
        public int getViewHorizontalDragRange(View child) {
            return super.getViewHorizontalDragRange(child);
        }

        /**
         * view滑动后的回调
         * @param changedView
         * @param left
         * @param top
         * @param dx   x轴方向的改编值
         * @param dy
         */
        @Override
        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
            super.onViewPositionChanged(changedView, left, top, dx, dy);
            Log.i(TAG, "onViewPositionChanged-->" + "dx=" + dx);
            //重新布局子view的位置
            if (changedView == contentView) {
                deleteView.layout(deleteView.getLeft() + dx, 0, deleteView.getRight() + dx, deleteView.getBottom());
            } else if (changedView == deleteView) {
                contentView.layout(contentView.getLeft() + dx, 0, contentView.getRight() + dx, contentView.getBottom());
            }
        }

        /**
         * TouchUp的回调
         * @param releasedChild
         * @param xvel
         * @param yvel
         */
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            super.onViewReleased(releasedChild, xvel, yvel);

            if (contentView.getLeft() < -deleteViewWidth / 2) {   //滑动条打开状态
                mViewDragHelper.smoothSlideViewTo(contentView, -deleteViewWidth, 0);
            } else {          //滑动条关闭状态
                mViewDragHelper.smoothSlideViewTo(contentView, 0, 0);
            }
            //
            ViewCompat.postInvalidateOnAnimation(SwipeView.this);  //动画刷新
        }
    };

动画效果

Scroller帮助计算好view在某个时间点会处于某个位置,达到动画的效果


    @Override
    public void computeScroll() {
        super.computeScroll();
        if(mViewDragHelper.continueSettling(true)){     //内部有Scroller计算位置和移动
            ViewCompat.postInvalidateOnAnimation(SwipeView.this);       //刷新当前view
        }

    }

ListView中的滑动删除效果

完整代码

github

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章