View中scroll相关方法

public void computeScroll() { //空实现 ,子 view重写时用于计算滚动并实现滚动动作 }

public void scrollTo(int x,int y) {//view的(left,top)滚动到一个点(x,y)  赋值

        if (mScrollX != x ||mScrollY != y) {

            int oldX = mScrollX;

            int oldY = mScrollY;

            mScrollX = x;

            mScrollY = y;

            invalidateParentCaches();

            onScrollChanged(mScrollX, mScrollY, oldX, oldY);

            if (!awakenScrollBars()) {

                postInvalidateOnAnimation();

            }

        }

}

public void scrollBy(int x,int y) {//view的(left,top)需要滚动的距离为(x,y)累计

     scrollTo(mScrollX + x, mScrollY + y); 

}


public finalint getScrollX() {

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

}


public finalint getScrollY() {

     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 Scroller(Context context) {

        this(context, null);

    }

   public Scroller(Context context, Interpolator interpolator) {//使用了插值器Interpolator

        this(context, interpolator,

                context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB);

    }

   public Scroller(Context context, Interpolator interpolator,boolean flywheel) {

        mFinished = true;

        mInterpolator = interpolator;

        mPpi = context.getResources().getDisplayMetrics().density * 160.0f;

        mDeceleration = computeDeceleration(ViewConfiguration.getScrollFriction());

        mFlywheel = flywheel;


        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 dy) {

        startScroll(startX, startY, dx, dy, DEFAULT_DURATION);

    }

//开始滚动 (,,,,滚动持续时间)

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; //需要滚动到的最终点x

        mFinalY = startY + dy; //需要滚动到的最终点y

        mDeltaX = dx;  

        mDeltaY = dy;

        mDurationReciprocal = 1.0f / (float)mDuration;

    }


//基于手势的滑动

public void fling(int startX,int startY,int velocityX,int velocityY,

            int minX, int maxX, int minY, int maxY) {

    ...

}

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

     }

     invalidate后,会再次执行view.computeScroll(); 直至滚动到最终需要的目标点

     

 2.fling-mode 一般使用流程

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

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

    也可以用GestureDetector来监听touchevent,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/


更多相关文章

  1. 解决android sdk docs帮助文档打开慢的问题
  2. 使用DialogFragment
  3. Android(安卓)bind其他或第三方APK Service方法
  4. android 拍照获得的照片太小太娇气 的 解决方法
  5. Android内核解读-Android系统的开机启动过程
  6. Android中进入页面默认定位到ListView的第一条数据解决方法
  7. Android(安卓)Scroller的理解
  8. Android(安卓)View初始化基本流程
  9. 学习ContentProvider---之一:查询数据库

随机推荐

  1. Android SQLite数据库升级的问题
  2. Android下USB Accessory的实现分析 (四)---
  3. Android 修改app图标和名称的方法
  4. Android 使用jdk1.8新特性之lambda表达式
  5. Android四大组件和Intent一览
  6. Android基本之SharedPreferences和File
  7. 通过超链接打开一些常见app(android:schem
  8. 六款值得推荐的android(安卓)开源框架简介
  9. Android 老罗视频教程笔记
  10. zjujoe的专栏都是月亮惹的祸--linux andr