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

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