Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> View 滑動的實現

View 滑動的實現

編輯:關於Android編程

復習一下view滑動的幾種實現方式

1.通過layout實現

通過不斷重新layout view 達到滑動的效果。

    @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);

                //與上面的方法是等效,直接設置偏移量
                //offsetLeftAndRight(offsetX);
                //offsetTopAndBottom(offsetY);
                break;
        }
        return true;
    }

這裡需要注意,我們使用的getX 和getY 方法,如果使用 getRawX 和getRawY 方法,那麼代碼就要做些許改變。就是在重新layout後,我們需要重新賦值 lastX和lastY的值。 否則就會出現意想不到的結果哦。 有興趣的朋友可以試一試,可以加深對於這兩個方法的認識。

2.通過改變LayoutParams

layoutparams 保存了view的布局參數,我們可以通過不斷修改其參數,重新設置,達到滑動效果。需要修改的參數就是自己與父view的邊距。注意通過getLayotParams 方法獲取layoutparams時類型要根據其父view的類型來確定。

    @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的類型了
                ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();
                //LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();
                layoutParams.leftMargin = getLeft() + offsetX;
                layoutParams.topMargin = getTop() + offsetY;
                setLayoutParams(layoutParams);
                break;
        }
        return true;
    }

3.通過view自己的scrollTo和scrollBy 來實現

srollTo(x,y) 表示移動到位置(x,y)處。
srollBy(dx,dy) 表示在當前位置的基礎上移動 dx和dy的距離。dx和dy為偏移量。

 public void scrollBy(int x, int y) {  
       scrollTo(mScrollX + x, mScrollY + y);  
   }  

同時需要注意,他們移動的都是view自己的內容。對應 viewgroup移動的就是自己的子view。所以父viewgroup中的素有view都會一起移動哦。

    @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;
                //這裡要注意,offsetx為我們相對於父viewgroup移動的距離,但是,這裡我們調用的是讓父viewgroup移動的方法,所以參考系,相對於反轉了,所以要在前面加上負號。
                ((View) getParent()).scrollBy(-offsetX, -offsetY);
                break;
        }
        return true;
    }

4.scroller

與上面的不同,scroller主要是用於當沒有用戶手動操作的時候,我們用來連續移動 view 的方式。需要配合view 的computeScroll 和scrollTo方法配合使用。該方法會在view 的draw方法中被調用。

    @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;
    }

流程如下:

流程圖

說的通俗一點就是:scroller 每次提供一個值 mScroller.getCurrX(),然後view scrollTo這個位置,然後view 重新繪制,然後又調用 computeScroll 方法,然後scroler 又提供一個值mScroller.getCurrX() 又重繪。 相當於一個死循環,不停地移動。 循環的出口就是mScroller.computeScrollOffset() 方法。 這個方法有兩個作用,一個是返回是否滑動到了指定的位置,二是每次調用時會不斷的改變 mScroller.getCurrX()的值,讓這個越來越接近滑動結束的值,知道達到滑動結束的值時,該方法的返回值也就變成了false。<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPr+0v7RzY3JvbGxlcrXEsr+31rT6wuujrMrXz8jKx8bkubnU7Lqvyv2jrMbkyrXSsr7Nysez9cq8u6/By9K70Km7rLavtcTOu9bDus3Ksbzk1rWjujwvcD4NCjxwcmUgY2xhc3M9"brush:java;"> public void startScroll(int startX, int startY, int dx, int dy, int duration) { mMode = SCROLL_MODE; mFinished = false; mDuration = duration; mStartTime = AnimationUtils.currentAnimationTimeMillis(); mStartX = startX; mStartY = startY; mFinalX = startX + dx; mFinalY = startY + dy; mDeltaX = dx; mDeltaY = dy; mDurationReciprocal = 1.0f / (float) mDuration; // This controls the viscous fluid effect (how much of it) mViscousFluidScale = 8.0f; // must be set to 1.0 (used in viscousFluid()) mViscousFluidNormalize = 1.0f; mViscousFluidNormalize = 1.0f / viscousFluid(1.0f); }

然後是其 computeScrollOffset()方法

public boolean computeScrollOffset() {  
    if (mFinished) {  
        return false;  
    }  

    int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);  

    if (timePassed < mDuration) {  
        switch (mMode) {  
        case SCROLL_MODE:  
            float x = (float)timePassed * mDurationReciprocal;  

            if (mInterpolator == null)  
                x = viscousFluid(x);   
            else  
                x = mInterpolator.getInterpolation(x);  

            mCurrX = mStartX + Math.round(x * mDeltaX);  
            mCurrY = mStartY + Math.round(x * mDeltaY);  
            break;  
        case FLING_MODE:  
            float timePassedSeconds = timePassed / 1000.0f;  
            float distance = (mVelocity * timePassedSeconds)  
                    - (mDeceleration * timePassedSeconds * timePassedSeconds / 2.0f);  

            mCurrX = mStartX + Math.round(distance * mCoeffX);  
            // Pin to mMinX <= mCurrX <= mMaxX  
            mCurrX = Math.min(mCurrX, mMaxX);  
            mCurrX = Math.max(mCurrX, mMinX);  

            mCurrY = mStartY + Math.round(distance * mCoeffY);  
            // Pin to mMinY <= mCurrY <= mMaxY  
            mCurrY = Math.min(mCurrY, mMaxY);  
            mCurrY = Math.max(mCurrY, mMinY);  

            break;  
        }  
    }  
    else {  
        mCurrX = mFinalX;  
        mCurrY = mFinalY;  
        mFinished = true;  
    }  
    return true;  
}  

5.ViewDragHelper

ViewDragHelper是v4包中Google 為我們封裝了Scroller的一個工具類。為我們實現不同的滑動等效果提供的一種方案。
其一般使用在ViewGroup中,通過其工廠方法創建其實例,通過其實例來處理View的事件和移動。 相當於我們把View(子View)都交給她來處理了。

首先當然是先創建其實例對象
mViewDragHelper = ViewDragHelper.create(this, callback);
ViewGroup的事件交給mViewDragHelper處理
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return mViewDragHelper.shouldInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mViewDragHelper.processTouchEvent(event);
        return true;
    }
因為同樣是 通過Scroller實現滑動的,所以我們也需要重寫computeScroll方法
    @Override
    public void computeScroll() {
        if (mViewDragHelper.continueSettling(true)) {
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }

這些也都是固定寫法了。

最為關鍵的就是 在創建mViewDragHelper時我們傳入的callback對象,這個是我們要自己去實現的。通過這個回調,我們可以實現我們自己需要的滑動效果。
    private ViewDragHelper.Callback callback =
            new ViewDragHelper.Callback() {

                //是否處理 該view也就是參數 child。返回 true 處理,否則這忽略噶子view。
                @Override
                public boolean tryCaptureView(View child, int pointerId) {
                    return mchild == child;
                }

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

                // 當拖拽狀態改變時回調 如:STATE_IDLE、STATE_DRAGGING、STATE_SETTLING
                @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);
                    //手指抬起後緩慢移動到指定位置
                    //相當於Scroller的startScroll方法
                     mViewDragHelper.smoothSlideViewTo(mchild, 0, 0);
                     ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
                }
            };

這樣,我們就完成了想要的滑動了。之後,會分析一下它的源碼,看看到底如何實現的。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved