1. 程式人生 > >Android實現滑動的七種方法

Android實現滑動的七種方法

1.layout方法

每次移動後,呼叫layout()方法對自己重新佈局從而達到移動的效果

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 記錄觸控點座標
                lastX = x;
                lastY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                // 計算偏移量
                int offsetX = x - lastX;
                int offsetY = y - lastY;
                // 在當前left、top、right、bottom的基礎上加上偏移量
                layout(getLeft() + offsetX,
                        getTop() + offsetY,
                        getRight() + offsetX,
                        getBottom() + offsetY);
                break;
        }
        return true;
    }

2.offsetLeftAndRight()和offsetTopAndBottom()

系統提供的一個對左右、上下移動的API封裝,效果和使用layout()一樣

offsetLeftAndRight(offsetX);
offsetTopAndBottom(offsetY);

3.LayoutParams

LayoutParams裡儲存了View的佈局引數,通常通過改變LayoutParams來改變一個View的位置都是通過改變這個View的Margin屬性。

            case MotionEvent.ACTION_MOVE:
                // 計算偏移量
                int offsetX = x - lastX;
                int offsetY = y - lastY;
                ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();
                layoutParams.leftMargin = getLeft() + offsetX;
                layoutParams.topMargin = getTop() + offsetY;
                setLayoutParams(layoutParams);
                break;

4.ScrollTo與ScrollBy

這兩個方法移動的是View的內容,我們應該在要移動的View所在的ViewGroup中來使用這兩個方法。

這兩個方法的區別是scrollTo(x, y)表示移動到一個具體的座標點(x, y),而scrollBy(dx, dy)表示移動的增量為dx、dy。

同時要想實現跟隨手指一動而華東的效果,需要將偏移量設定為負數

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastX = (int) event.getX();
                lastY = (int) event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                int offsetX = x - lastX;
                int offsetY = y - lastY;
                ((View) getParent()).scrollBy(-offsetX, -offsetY);
                break;
        }
        return true;
    }

5.Scroller類

通過Scroller類可以實現平滑移動的效果,而不再是瞬間完成的動作。

使用Scroller類需要三個步驟:

  • 初始化Scroller
  • 重寫computeScroll()方法。用來判斷是否完成了整個滑動
  • 開始滑動。startScroll(int startX, int startY, int dx, int dy, int duration)和startScroll(int startX, int startY, int dx, int dy)方法,區別是其中一個具有指定時長
    private void ininView(Context context) {
        // 初始化Scroller
        mScroller = new Scroller(context);
    }

    @Override
    public void computeScroll() {
        super.computeScroll();
        // 判斷Scroller是否執行完畢
        if (mScroller.computeScrollOffset()) {
            ((View) getParent()).scrollTo(
                    mScroller.getCurrX(),
                    mScroller.getCurrY());
            // 通過重繪來不斷呼叫computeScroll
            invalidate();
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastX = (int) event.getX();
                lastY = (int) event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                int offsetX = x - lastX;
                int offsetY = y - lastY;
                ((View) getParent()).scrollBy(-offsetX, -offsetY);
                break;
            case MotionEvent.ACTION_UP:
                // 手指離開時,執行滑動過程
                View viewGroup = ((View) getParent());
                mScroller.startScroll(
                        viewGroup.getScrollX(),
                        viewGroup.getScrollY(),
                        -viewGroup.getScrollX(),
                        -viewGroup.getScrollY());
                invalidate();
                break;
        }
        return true;
    }

6.屬性動畫

詳情見屬性動畫的介紹

7.ViewDragHelper

使用步驟:

  • 初始化ViewDragHelper
mViewDragHelper = ViewDragHelper.create(this, callback);
  • 攔截事件
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return mViewDragHelper.shouldInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //將觸控事件傳遞給ViewDragHelper,此操作必不可少
        mViewDragHelper.processTouchEvent(event);
        return true;
    }
  • 處理computeScroll()
    @Override
    public void computeScroll() {
        if (mViewDragHelper.continueSettling(true)) {
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }
  • 處理回撥CallBack
    private ViewDragHelper.Callback callback =
            new ViewDragHelper.Callback() {

                // 何時開始檢測觸控事件
                @Override
                public boolean tryCaptureView(View child, int pointerId) {
                    //如果當前觸控的child是mMainView時開始檢測
                    return mMainView == child;
                }

                // 觸控到View後回撥
                @Override
                public void onViewCaptured(View capturedChild,
                                           int activePointerId) {
                    super.onViewCaptured(capturedChild, activePointerId);
                }

                // 當拖拽狀態改變,比如idle,dragging
                @Override
                public void onViewDragStateChanged(int state) {
                    super.onViewDragStateChanged(state);
                }

                // 當位置改變的時候呼叫,常用與滑動時更改scale等
                @Override
                public void onViewPositionChanged(View changedView,
                                                  int left, int top, int dx, int dy) {
                    super.onViewPositionChanged(changedView, left, top, dx, dy);
                }

                // 處理垂直滑動
                @Override
                public int clampViewPositionVertical(View child, int top, int dy) {
                    return 0;
                }

                // 處理水平滑動
                @Override
                public int clampViewPositionHorizontal(View child, int left, int dx) {
                    return left;
                }

                // 拖動結束後呼叫
                @Override
                public void onViewReleased(View releasedChild, float xvel, float yvel) {
                    super.onViewReleased(releasedChild, xvel, yvel);
                    //手指擡起後緩慢移動到指定位置
                    if (mMainView.getLeft() < 500) {
                        //關閉選單
                        //相當於Scroller的startScroll方法
                        mViewDragHelper.smoothSlideViewTo(mMainView, 0, 0);
                        ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
                    } else {
                        //開啟選單
                        mViewDragHelper.smoothSlideViewTo(mMainView, 300, 0);
                        ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
                    }
                }
            };

參考文章:《Android群英傳》