Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Scroller的學習

Scroller的學習

編輯:關於Android編程

前言

一直對Scroller這個類不太熟悉,之前老是在網上找著看,但是過不了多長時間後就忘記了,今天來整理一下
先看一下Scroller裡面的方法:
http://api.apkbus.com/reference/android/widget/Scroller.html


說明

為了理解方便,拿SlideView來做說明,關於SlideView的demo網上有很多,這裡為了講解主要貼出SlideView:

public class SlideView extends LinearLayout {
      private Context mContext;

        private LinearLayout mViewContent;

        private LinearLayout mHolder;

        private TextView tv_delete;

        // 彈性滑動對象,實現View平滑滾動的一個幫助類
        private Scroller mScroller;

        // 滑動回調接口,用來向上層通知滑動事件
        private OnSlideListener mOnSlideListener;

        private int mHolderWidth = 100;

        private int mLastX = 0;

        private int mLastY = 0;

        private static final int TAN = 2;


        public SlideView(Context context) {
            super(context);
            initView();
        }

        public SlideView(Context context, AttributeSet attrs) {
            super(context, attrs);
            initView();
        }


        private void initView(){
            mContext = getContext();
            mScroller = new Scroller(mContext);
            setOrientation(LinearLayout.HORIZONTAL);
            setGravity(Gravity.CENTER_VERTICAL);
            //將R.layout.slide_view 添加到this, View view=View.inflate(this,R.layout.*,null);是生成一個新的View
            View.inflate(mContext, R.layout.slide_view, this);
            mViewContent = (LinearLayout)findViewById(R.id.view_content);
            mHolder = (LinearLayout)findViewById(R.id.holder);

            tv_delete = (TextView)findViewById(R.id.delete);

        }


        public void setButtonText(CharSequence text){
            tv_delete.setText(text);
        }


        public void setContentView(View view){
            mViewContent.addView(view);
        }

        public void onRequireTouchEvent(MotionEvent event){
                // 獲取點擊的坐標
                int x = (int)event.getX();
                int y = (int)event.getY();
                //當前view的左上角相對於母視圖的左上角的X軸偏移量。
                int scrollX = getScrollX();
                switch (event.getAction()){
                    case MotionEvent.ACTION_DOWN:
                        if(!mScroller.isFinished()){
                            mScroller.abortAnimation();
                        }
                        if(mOnSlideListener != null){
                            mOnSlideListener.onSlide(this, OnSlideListener.SLIDE_STATUS_START_SCROLL);
                        }

                        break;

                    case MotionEvent.ACTION_MOVE:
                        //增量
                        int deltaX = x - mLastX;
                        int deltaY = y - mLastY;
                        if(Math.abs(deltaX) < Math.abs(deltaY)*TAN){
                            // 滑動不滿足條件 不做橫向滑動
                            break;
                        }
                            /**
     * 1. 這個SlideView相對於上次偏移的距離減去手指這次move的相對於上次move的增量(相對偏移量?)
     *
     * 2. 舉個例子:如果現在手指滑動,ACTION_DOWN的坐標為(100,0),現在開始MOVE滑動(ACTION_MOVE)第一個MOVE的坐標為(50,0)
     *
     *    即deltaX=50-100,第一個MOVE時scrollX = 0,newScrollX = scrollX - deltaX;newScrollX = 50
     *    this.scrollTo(newScrollX, 0);view是偏移50,
     *
     *    第二個MOVE的到達坐標為(10,0),而mLastX是第一個MOVE的x坐標(mLastX = 50)
     *    deltaX=10-50 ,deltaX = -40 ;scrollX = 50  newScrollX = scrollX - deltaX;newScrollX = 90
     *    this.scrollTo(newScrollX, 0);view是偏移90,
     *
     */
                        int newScrollX = scrollX - deltaX;
                        if(deltaX != 0){
                            if(newScrollX < 0){
                                newScrollX = 0;
                            }else if(newScrollX > mHolderWidth){
                                newScrollX = mHolderWidth;
                            }
                            //會觸發computeScroll()
                            this.scrollTo(newScrollX, 0);
                        }

                        break;

                    case MotionEvent.ACTION_UP:
                        int newScrollx = 0;
                        //如果SlideView的偏移量大於默認要滑動距離的3/4,newScrollx=mHolderWidth,否則 newScrollx = 0;
                        if(scrollX - mHolderWidth*0.75 > 0){
                            newScrollx = mHolderWidth;
                        }

                        this.smoothScrollTo(newScrollx, 0);
                        // 通知上層滑動事件
                        if(mOnSlideListener != null){
                            mOnSlideListener.onSlide(this, newScrollx == 0 ? OnSlideListener.SLIDE_STATUS_OFF
                                    : OnSlideListener.SLIDE_STATUS_ON);
                        }

                        break;

                    default:
                        break;
                }

                mLastX = x;
                mLastY = y;
        }


        /**
         * 調用此方法滾動到目標位置
         * @param fx  目標x坐標
         * @param fy  目標Y坐標
         */
        private void smoothScrollTo(int fx, int fy){
            int scrollX = getScrollX();
            int dx = fx - scrollX;

            int scrollY = getScrollY();
            int dy = fy - scrollY;
            //手指up之後從現在的位置偏移到scrollX+dx位置,dx是增量,觸發computeScroll
            mScroller.startScroll(scrollX, scrollY, dx, dy, Math.abs((dx)*3));

            invalidate();
        }


        /**
         * 由mScroller記錄/計算好View滾動的位置後,最後由View的computeScroll(),完成實際的滾動
         */
        @Override
        public void computeScroll() {
            //先判斷mScroller滾動是否完成
            if(mScroller.computeScrollOffset()){
                //這裡調用View的scrollTo()完成實際的滾動
                scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
                //必須調用該方法,否則不一定能看到滾動效果
                postInvalidate();
            }
            super.computeScroll();
        }


        /**
         * 設置滑動回調
         * @param onSlideListener
         */
        public void setOnSlideListener(OnSlideListener onSlideListener){
            this.mOnSlideListener = onSlideListener;
        }


        public interface OnSlideListener {
            public static final int SLIDE_STATUS_OFF = 0;
            public static final int SLIDE_STATUS_START_SCROLL = 1;
            public static final int SLIDE_STATUS_ON = 2;

            public void onSlide(View view, int status);
        }

}

先說一下實現的具體思路,SlideView是一個橫向LinearLayout,作為父布局,它裡面有兩個child(當然可以更多),第一個child設置寬度充滿整個父布局,這樣的第二個child就會被擠出屏幕外面,要明確一點SlideView是無窮大的,你看到的只是屏幕顯示的那一塊,然後通過SlideView的scrollTo,讓SlideView整個平移,這樣第二個child就會顯示出來

具體講解一下:
1.ACTION_DOWN:mScroller停止動畫,這個沒什麼說的

2.ACTION_MOVE:舉個例子:SlideView已經偏移了scrollX,你下次move觸發的時候只需要偏移scrollX - deltaX就可以了,scrollTo是相對於上次偏移,getScrollX卻是向對於開始時的位置

3.ACTION_UP:在UP之前可以看到mScroller沒有做任何關於滾動的的動作,up的時候調用了
private void smoothScrollTo(int fx, int fy){
int scrollX = getScrollX();
int dx = fx - scrollX;

        int scrollY = getScrollY();
        int dy = fy - scrollY;
        //手指up之後從現在的位置偏移到scrollX+dx位置,dx是增量,觸發computeScroll
        mScroller.startScroll(scrollX, scrollY, dx, dy, Math.abs((dx)*3));

        invalidate();
    }

觸發了computeScroll()
@Override
public void computeScroll() {
//先判斷mScroller滾動是否完成
if(mScroller.computeScrollOffset()){
//這裡調用View的scrollTo()完成實際的滾動
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
//必須調用該方法,否則不一定能看到滾動效果
postInvalidate();
}
super.computeScroll();
}
computeScroll裡面做了什麼??先mScroller.computeScrollOffset()判斷mScroller滾動是否完成,computeScrollOffset做了什麼呢?
public boolean computeScrollOffset() {
if (mFinished) {
return false;
}

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

    if (timePassed < mDuration) {
        switch (mMode) {
        case SCROLL_MODE:
            float x = 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;

}

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

可以看出int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);mStartTime = AnimationUtils.currentAnimationTimeMillis();獲取過了多長時間,
然後if (timePassed < mDuration) ,看一下有沒有到達設置的時間,
然後一通計算mCurrX = mStartX + Math.round(x * mDeltaX);(計算是為了在mDuration時間內完成滾動dx)得到mCurrX
,然後回到computeScroll(), scrollTo(mScroller.getCurrX(), mScroller.getCurrY());在次偏移mCurrX ,
然後回調computeScroll,直到滾動結束

注意:scrollTo(),如果第一次你在x軸向左上偏移了10,下次再向左偏移10的話,相當於較之原點你已經移到了20,所以說getscrollx也是基於開始位置的偏移,現在getscrollx是20,scrollBy()是相對於你上次移動

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