scroller的使用和view的位移

scroller的一些用法
view中有两个方法 public void scrollTo(int x, int y)和 public void scrollBy(int x, int y)  通俗来说,scrollTo是到坐标为x和y的位置,scrollBy是继续偏移x和y个单位的坐标。 看源代码
 public void scrollBy(int x, int y) {  
      scrollTo(mScrollX + x, mScrollY + y);  
  }  
发现scrollBy是调用了scrollTo方法,在原先参数的基础上添加了原始坐标位置,相加后传递给了scrollTo方法。再看看scrollTo方法的源码
public void scrollTo(int x, int y) {  
    // 偏移位置发生了改变  mScrollX 和mScrollY 是view现在所在的位置
    if (mScrollX != x || mScrollY != y) {  
        int oldX = mScrollX;  
        int oldY = mScrollY;  
        mScrollX = x;  //赋新值,保存当前便宜量  
        mScrollY = y;  
        //回调onScrollChanged方法  自己可以实现该接口
        onScrollChanged(mScrollX, mScrollY, oldX, oldY);  
        if (!awakenScrollBars()) {  
            invalidate();  //一般都会引起重绘  
        }  
    }  
}  


在scrollTo方法里面,如果控件内容顶着左上角,x值为正值,则整个控件里面的内容向左移动,y值为正值,则控件里面的内容向上移动;x和y为负值,则移动方向相反。简单的看成x轴向左为正,y轴向上为正的坐标轴即可。以控件左上定点为(0,0)坐标轴。
如果想获取view的偏移量,可以调用view向外边暴露的方法,getScrollX()方法和getScrollY()方法即可。
如果我们想在界面上移动view,比如说在scrollView中移动子控件,理论上来说上面两个方法够用,但有个弊端是移动速度太快,几乎是瞬移,用户还没看到控件的滑动效果,结果控件一瞬间就到目的地了,体验不好,基于此,google推出了Scroller辅助类,把view的位移速度给降了下来,并且可以人为控制。
Scroller  有n组成员变量,都是相对应的,
public class Scroller  {  
  
    private int mStartX;    //起始坐标点 ,  X轴方向  
    private int mStartY;    //起始坐标点 ,  Y轴方向  
    private int mCurrX;     //当前坐标点  X轴, 即调用startScroll函数后,经过一定时间所达到的值  
    private int mCurrY;     //当前坐标点  Y轴, 即调用startScroll函数后,经过一定时间所达到的值  
     
    private float mDeltaX;  //应该继续滑动的距离, X轴方向  
    private float mDeltaY;  //应该继续滑动的距离, Y轴方向  
    private boolean mFinished;  //是否已经完成本次滑动操作, 如果完成则为 true  
 
    //构造函数  
    public Scroller(Context context) {  
        this(context, null);  
    }  
    public final boolean isFinished() {  
        return mFinished;  
    }  
    //强制结束本次滑屏操作  
    public final void forceFinished(boolean finished) {  
        mFinished = finished;  
    }  
    public final int getCurrX() {  
        return mCurrX;  
    }  
      
    // 根据当前已经消逝的时间计算当前的坐标点,保存在mCurrX和mCurrY值中  返回值判断是否完成
    public boolean computeScrollOffset() {  
        if (mFinished) {  //已经完成了本次动画控制,直接返回为false  
            return false;  
        }  
        int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);  
        if (timePassed < mDuration) {  
            switch (mMode) {  
            case SCROLL_MODE:  
                float x = (float)timePassed * mDurationReciprocal;  
                ...  
                mCurrX = mStartX + Math.round(x * mDeltaX);  
                mCurrY = mStartY + Math.round(x * mDeltaY);  
                break;  
            ...  
        }  
        else {  
            mCurrX = mFinalX;  
            mCurrY = mFinalY;  
            mFinished = true;  
        }  
        return true;  
    }  
    //开始一个动画,由起点(startX , startY)在duration时间内进(dx,dy)个单位,到达坐标为(startX+dx , startY+dy)位置为止 
    public void startScroll(int startX, int startY, int dx, int dy, int duration) {  
        mFinished = false;  
        mDuration = duration;  
        mStartTime = AnimationUtils.currentAnimationTimeMillis();  
        mStartX = startX;       mStartY = startY;  
        mFinalX = startX + dx;  mFinalY = startY + dy;  
        mDeltaX = dx;            mDeltaY = dy;  
        ...  
    }  
}  


在自定义view时,要new一个Scroller,并且重写
public void computeScroll() {   
          
    } 
方法,在里面写一些固定的判断。
比如在view里面对外暴露一个函数
 public void startMove(){  
        //使用动画控制偏移过程 , 2s内到位  
        mScroller.startScroll(2 * getWidth(), 0, getWidth(), 0,2000);  
        //其实点击按钮的时候,系统会自动重新绘制View,我们还是手动加上吧。  
        invalidate();  
          
    }  


 public void computeScroll() {      
        Log.e(TAG, "移动了");  
        // 如果返回true,表示动画还没有结束,只有在startScroll完成时 才会为false  
        if (mScroller.computeScrollOffset()) {  
            Log.e(TAG, mScroller.getCurrX() + "======" + mScroller.getCurrY());  
            // 产生了动画效果,根据当前值 每次滚动一点  
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());  
            //此时同样也需要刷新View ,否则效果可能有误差  
            postInvalidate();  
        }  
        else  
            Log.i(TAG, "移动完成了");  
    }  


上面就这么简单,view就移动了。但是有一点需要分辨,就是
mScroller.startScroll(getWidth(), 0, 2*getWidth(), 0,2000);  这个方法,也就是scroller中的
public void startScroll(int startX, int startY, int dx, int dy, int duration)
中的参数的值,如果dx为正数,view向左滑动,dy为正值,view向上滑动,
scroller体系构建的左边体系是x轴向左为正方向,y轴向上为正方向,原点坐标轴为屏幕左上角。所以参数方面和上述的scrollBy(int x, int y)方法,如果参数相同的话,会发现view的移动方向是相反的,这点一定要分辨清楚,不要弄混了。实际上可以理解为是view里面的内容在移动,而非view在动。


手指触摸滑动也有个辅助类 VelocityTracker类
 public void computeCurrentVelocity (int units)
   //功能:以每像素units单位考核移动速率,赋予值1000或600都行
            public float getXVelocity ()
//x轴移动速率
一般是在view的onTouchEvent(MotionEvent event)方法里调用,先new一个对象,然后把触发事件给添加进去
//获得VelocityTracker对象,并且添加滑动对象  
        if (mVelocityTracker == null) {  
            mVelocityTracker = VelocityTracker.obtain();  
        }  
        mVelocityTracker.addMovement(event);  
关键起作用的是在MotionEvent.ACTION_UP里面,屏幕在滑动,手指头突然离开屏幕,这时候控件一般还要在缓冲滑动一会,就像快速滑动listview时,手指突然离开屏幕,listview还要滑动一会慢慢停止,这样体验比较好,手指抬起后,就是MotionEvent.ACTION_UP里面的逻辑了
设置参数,拿到移动的速率
 velocityTracker.computeCurrentVelocity(1000);  
            //计算速率  
  int velocityX = (int) velocityTracker.getXVelocity() ; 
然后做逻辑判断,看 velocityX 的绝对值是否比自定义的要大,如果大,可以做一些页面的滑动操作,比如调用 mScroller.startScroll(getScrollX(), 0, dx, 0,Math.abs(dx) * 2);    方法,页面会慢慢减低滑动速率,最终到指定的位置。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值