zoukankan      html  css  js  c++  java
  • Scroller 和 ScrollTo ScrollBy的结合使用

     我们知道想把一个View偏移至指定坐标(x,y)处,利用scrollTo()方法直接调用就OK了,但我们不能忽视的是,该方法本身来的的副作用:非常迅速的将View/ViewGroup偏移至目标点,而没有对这个偏移过程有任何控制,对用户而言可能是不太友好的。于是,基于这种偏移控制,Scroller类被设计出来了,该类的主要作用是为偏移过程制定一定的控制流程(后面我们会知道的更多),从而使偏移更流畅,更完美。

    getScrollX, Return the scrolled left position of this view. This is the left edge of the displayed part of your view,in pixels.

    view实际内容占的大小(画布上画的内容)可能远远超过其显示区域的大小(view布局大小),ScrollX,是当前显示区域的左边界在画布坐标系中的位置。

    画布坐标系也是左上角为原点

    getScrollY, 同上是显示区域的上边界在画布坐标系中的位置。

    scrollBy,scrollTo,移动画布,在画布坐标系上移动x,y轴位置,调整显示区域。

    scrollBy(20)相当于画布向左移动了20px

    scrollX 加正数表示向左移动

    scrollY加正数表示向上移动

    模拟Scroller类的实现功能:

          假设从上海做动车到武汉需要10个小时,行进距离为1000km ,火车速率200/h 。采用第一种时间控制方法到达武汉的

       整个配合过程可能如下:

            我们每隔一段时间(例如1小时),计算火车应该行进的距离,然后调用scrollTo()方法,行进至该处。10小时过完后,

        我们也就达到了目的地了。

    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;  
        }  
         /* Call this when you want to know the new location.  If it returns true, 
         * the animation is not yet finished.  loc will be altered to provide the 
         * new location. */    
        //根据当前已经消逝的时间计算当前的坐标点,保存在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;  
            ...  
        }  
    } 

    其中比较重要的两个方法为:

               public boolean computeScrollOffset()

    函数功能说明:根据当前已经消逝的时间计算当前的坐标点,保存在mCurrX和mCurrY值中

               public void startScroll(int startX, int startY, int dx, int dy, int duration)

     函数功能说明:开始一个动画控制,由(startX , startY)在duration时间内前进(dx,dy)个单位,到达坐标为 (startX+dx , startY+dy)处。

    computeScroll()方法介绍

          为了易于控制滑屏控制,Android框架提供了 computeScroll()方法去控制这个流程。在绘制View时,会在draw()过程调用该

      方法。因此, 再配合使用Scroller实例,我们就可以获得当前应该的偏移坐标,手动使View/ViewGroup偏移至该处。该方法位于ViewGroup.java类中      

    第一、调用Scroller实例去产生一个偏移控制(对应于startScroll()方法),手动调用invalid()方法去重新绘制。

    第二、ViewGroup重绘时会调用computeScroll(), 剩下的就是在 computeScroll()里根据当前已经逝去的时间,获取当前 应该偏移的坐标(由Scroller实例对应的computeScrollOffset()计算而得),

    第三、当前应该偏移的坐标,调用scrollBy()方法去缓慢移动至该坐标处。

     

    public void startMove() {
            // 使用动画控制偏移过程 , 3s内到位
            mScroller.startScroll((curScreen - 1) * getWidth(), 0, getWidth(), 0, 3000);
            // 其实点击按钮的时候,系统会自动重新绘制View,我们还是手动加上吧。
            invalidate();
            // 使用scrollTo一步到位
            // scrollTo(curScreen * MultiScreenActivity.screenWidth, 0);
    }

    重写ViewGoup的computeScroll方法:

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

    public void startScroll(int startX, int startY, int dx, int dy, int duration)

    finish状态后,getCurrX得到的值是   startX + dx,

    原理即根据插值器和duration,将dx的值分成小片加到startX上,同理getCurrY

     

     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

     一个替代依靠invalide 和 computeScroll 来使用 Scroller的方法:

    private class FlingRunnable implements Runnable {
    
            private Scroller mScroller;
    
            public FlingRunnable() {
                mScroller = new Scroller(getContext());
            }
    
            public void startScroll(int distance) {
                //mScroller.startScroll(0, distance, 0, -distance, 1000);
                //调用scroller的方法
                
                
                post(this);
            }
    
            public void stop() {
                removeCallbacks(this);
                mScroller.forceFinished(true);
            }
    
            public void run() {
                final Scroller scroller = mScroller;
                boolean more = scroller.computeScrollOffset();
                
    
                if (more) {
                    // 在这里使用Scroller的x,y值
    
                    post(this);
                } else {
                    stop();
                }
            }
    
        }
  • 相关阅读:
    【Other】申请免费的SSL证书及部署Https协议
    【MySql】mysql-5.7.20-winx64安装配置
    【CSharp】C#程序使用.NET Reactor进行混淆加壳
    【Linux】Ubuntu安装Python3
    【Linux】Ubuntu安装Googlepinyin中文输入法
    【Linux】Ubuntu修改默认源
    【C/S】FIPS安全验证问题
    【Android】apk文件反编译
    笔记之《用python写网络爬虫》
    memcache (持续了解ing...)
  • 原文地址:https://www.cnblogs.com/zijianlu/p/2506495.html
Copyright © 2011-2022 走看看