View中scroll相关方法

public void computeScroll() { //空实现 ,子 view重写时用于计算滚动并实现滚动动作 }
public void scrollTo(int x,int y) {//view的(left,top)滚动到一个点(x,y)  赋值
if (mScrollX != x ||mScrollY
int oldX = mScrollX;
int oldY = mScrollY;
mScrollX
mScrollY
            invalidateParentCaches();
mScrollX, mScrollY, oldX, oldY);
if
                postInvalidateOnAnimation();
            }
        }
}
public void scrollBy(int x,int y) {//view的(left,top)需要滚动的距离为(x,y)累计
mScrollX + x, mScrollY
}

public finalint
return mScrollX;//最后一次滚动到的left坐标值
}

public finalint
return mScrollY;//最后一次滚动到的top坐标值
}


scroll 滚动结果的说明:

 不论是scrollTo还是scrollBy, 最后都是滚动到某一点(x,y)

  表现在界面上的变化就是,将内容区(x,y)位置,移动到屏幕的(0,0)坐标

 在SlidingMenu中,一般会先scrollTo(leftMenuWidth,0),表示右向滚动到x=leftMenuWidth,y=0的坐标点

      这时就是将此坐标点及之后的内容 移动到屏幕的(0,0)位置进行显示

> 如果View的内容要向左滚动,那么scrollX要传入正数;反之传负,向右滚

> 如果View的内容要向上滚动,那么scrollY要传入正数;反之传负,向下滚

形象的说:

  初始时,滚动器(Scroll)和View的内容的左顶点是重合的。

  当滚动器的x、y变化时,比如 x = 100,那此时 滚动器所在的位置(100, 0) 即成了View的(0, 0) 点了,

  view的x方向上即有 -100 的内容不可见了; 也就是说 内容向左滚动了

总的来说:就是view的滚动方向与屏幕坐标方向 相反


关于computeScroll:

  调用view.invalidate(); 会触发该方法。

  重写该方法时,内部一般使用一个android.widget.Scroller来处理滚动



android.widget.Scroller

View 的内容滚动器,不会改变 View 本身的位置,只是将内容进行滚动

构造方法:

public
this(context, null);
    }
   public Scroller(Context context, Interpolator interpolator) {//使用了插值器Interpolator
this(context, interpolator,
targetSdkVersion
    }
   public Scroller(Context context, Interpolator interpolator,boolean
mFinished = true;
mInterpolator
mPpi = context.getResources().getDisplayMetrics().density
mDeceleration
mFlywheel

mPhysicalCoeff = computeDeceleration(0.84f);// look and feel tuning
    }

一般使用第二个构造方法就可以,不想滚动效果太突兀,Interpolator传入一个LinearInterpolator(匀速运动)即可。


一些重要方法:

/*
 * 开始滚动 
startX,startY: 开始滚动的x,y方向的偏移量;正数将从左开始
距离dx,dy: 正数将向左移动
 */
public void startScroll(int startX,int startY,int dx,int
DEFAULT_DURATION);
    }
//开始滚动 (,,,,滚动持续时间)
public void startScroll(int startX,int startY,int dx,int dy,int
        mMode = SCROLL_MODE;
mFinished = false;  //滚动是否结束
mDuration
mStartTime
mStartX
mStartY
mFinalX
mFinalY
mDeltaX
mDeltaY
        mDurationReciprocal = 1.0f / (float)mDuration;
    }

//基于手势的滑动
public void fling(int startX,int startY,int velocityX,int
int minX, int maxX, int minY, int
    ...
}


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;
            case FLING_MODE:
                final float t = (float) timePassed / mDuration;
                final int index = (int) (NB_SAMPLES * t);
                float distanceCoef = 1.f;
                float velocityCoef = 0.f;
                if (index < NB_SAMPLES) {
                    final float t_inf = (float) index / NB_SAMPLES;
                    final float t_sup = (float) (index + 1) / NB_SAMPLES;
                    final float d_inf = SPLINE_POSITION[index];
                    final float d_sup = SPLINE_POSITION[index + 1];
                    velocityCoef = (d_sup - d_inf) / (t_sup - t_inf);
                    distanceCoef = d_inf + (t - t_inf) * velocityCoef;
                }

                mCurrVelocity = velocityCoef * mDistance / mDuration * 1000.0f;
                
                mCurrX = mStartX + Math.round(distanceCoef * (mFinalX - mStartX));
                // Pin to mMinX <= mCurrX <= mMaxX
                mCurrX = Math.min(mCurrX, mMaxX);
                mCurrX = Math.max(mCurrX, mMinX);
                
                mCurrY = mStartY + Math.round(distanceCoef * (mFinalY - mStartY));
                // Pin to mMinY <= mCurrY <= mMaxY
                mCurrY = Math.min(mCurrY, mMaxY);
                mCurrY = Math.max(mCurrY, mMinY);

                if (mCurrX == mFinalX && mCurrY == mFinalY) {
                    mFinished = true;
                }

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

computeScrollOffset 计算滚动的偏移量:

  两种滚动的模式:

  1.scroll-mode

      当知道滚动的目标距离时,调用startScroll方法后,即为这种模式。

      根据插入器Interpolator(如果有),算出一定时间内需要滚动的距离,

      最后将滚动到的目标点x,y存储在mCurrx和mCurrY中。

  2.fling-mode

      当不知道滚动的目标距离时,如ListView、GridView、ScrollView,

      根据手指滑动后弹起的速率来计算目标的滚动距离。

最后将滚动到的目标点x,y存储在mCurrx和mCurrY中。


Scroller 自身不能将view滚动,只是用于计算view的滚动值的。

 1.scroll-mode 一般使用流程

   可以在onTouchevent中,算出将要滚动的距离dx、dy后,调用scroller.startScroll(...);view.invalidate();

   在view的computeScroll中,调用if (scroller.computeScrollOffset()){ //滚动未完成

        //1.取出计算出的一定时间内需要滚动到的目标点

     

int x = scroller.getCurrX();
        int y = scroller.getCurrY();
        //执行滚动
        view.scrollTo(x, y);
        invalidate();
     }

computeScroll(); 直至滚动到最终需要的目标点

     

 2.fling-mode 一般使用流程

可以在onTouchEvent中,算出scroller.fling(...)需要的一些参数。

       速率值可以用VelocityTracker类的computeCurrentVelocity()方法来计算。

GestureDetector初始化时,重写一个onFling();

       即手势探测器,探测到fling的动作后,就会触发它。

    调用scroller.fling()后,算出滚动到的目标点。再在view.computeScroll中使用它,用法同上。


属性translationX/Y


//坐标关系
private void coordinatorRelation() {
    getLeft(); //view 的相对于父容器的左坐标
    getTop();
    getRight();
    getBottom();
//        setLeft(); //都有对应的 set 方法

    getX(); //x = left + translationX; 即view 的内容区的左上角 x 坐标
    getY(); //y = top + translationY;  即view 的内容区的左上角 y 坐标
//        setX(); //都有对应的 set 方法
    getTranslationX(); //左上角相对于父容器 x 方向的偏移量
    getTranslationY(); //左上角相对于父容器 y 方向的偏移量
//        setTranslationX(); //都有对应的 set 方法
}

使用改变该偏移量属性来进行滚动,需要配合动画;


动画在3.0后新增了属性动画Animator,即会改变 view 的位置;
而使用Animation,不会改变 View 的位置


一个兼容3.0下动画的兼容库:

https://github.com/JakeWharton/NineOldAndroids

http://nineoldandroids.com/