zoukankan      html  css  js  c++  java
  • Scroller类的使用总结

    Scroll类之所以不好理解是因为没有搞清楚View的绘制流程。

    1)简单来讲 viewgroup重绘时依次会调用  dispatchDraw -- drawChild --child.computeScroll()。

    computeScroll是一个空函数,可以在里面写代码。

    2)Scroller类一些api:

    mScroller.getCurrX() //获取mScroller当前水平滚动的位置
    mScroller.getCurrY() //获取mScroller当前竖直滚动的位置
    mScroller.getFinalX() //获取mScroller最终停止的水平位置
    mScroller.getFinalY() //获取mScroller最终停止的竖直位置
    mScroller.setFinalX(int newX) //设置mScroller最终停留的水平位置,没有动画效果,直接跳到目标位置
    mScroller.setFinalY(int newY) //设置mScroller最终停留的竖直位置,没有动画效果,直接跳到目标位置
    
    //滚动,startX, startY为开始滚动的位置,dx,dy为滚动的偏移量, duration为完成滚动的时间
    mScroller.startScroll(int startX, int startY, int dx, int dy) //使用默认完成时间250ms
    mScroller.startScroll(int startX, int startY, int dx, int dy, int duration)
    
    mScroller.computeScrollOffset() //返回值为boolean,true说明滚动尚未完成,false说明滚动已经完成。这是一个很重要的方法,通常放在View.computeScroll()中,用来判断是否滚动是否结束。

    其中非常重要的startScroll()和computeScrollOffset()函数。

    startScroll函数的功能是设置一些值,最重要的值是设置了一个滚动开始时间和持续时间,其源码如下:

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

    computeScrollOffset()是用来计算当前时间点理论上能够滚到的x,y坐标。

    如果滚动持续时间到了则返回false,否则返回true并计算坐标。mCurrX和mCurrY得到更新。源码如下:

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

    3)通过1、2我们可以知道如果要实现平滑滚动则需要在computeScroll函数里调用computeScrollOffset()来更新Scroller里面的mCurrX 和mCurrY,然后利用

    scrollTo(mCurrX, mCurrY) 来让View的x、y坐标滚动到指定位置。此时并不一定会导致view重绘,手动调用postInvalidate()自上而下重绘view树。

    注意scrollTo只会导致该view的内容发生偏移,并不会导致该view的位置偏移。比如对Button进行scrollTo 会导致Button里面的text发生偏移,而Button的位置不会发生偏移。

    4) 有了上面的分析后下面是一段小实例,单击按钮后,按钮会慢慢下移。

    CustomView.java:

    public class CustomView extends LinearLayout {
    
        private Scroller mScroller = null;
        private Context mContext;
        
        public CustomView(Context context) {
            super(context);
            mContext = context;
            init();
        }    
        public CustomView(Context context, AttributeSet attrs) {
            super(context, attrs);
            mContext = context;
            init();
        }
        
        private void init() {
            if (mScroller == null) {
                mScroller = new Scroller(mContext);        
            }            
            this.setOrientation(VERTICAL);
            Button btn = new Button(mContext);
            btn.setText("按钮");
            LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
            this.addView(btn, params);    
            this.setBackgroundColor(Color.YELLOW);
        }
            
        //调用此方法设置滚动到目标位置    
        public void smoothScrollTo(int fx, int fy) {
            int dx = fx - mScroller.getFinalX();
            int dy = fy - mScroller.getFinalY();
            smoothScrollBy(dx, dy);
        }
        
        //调用此方法设置滚动的相对偏移
        public void smoothScrollBy(int dx, int dy) {
            mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy, 10000);
            invalidate();
        }
        
        @Override
        public void computeScroll() {
            // TODO Auto-generated method stub
        
            //查看是否滚动结束了,true表示没有结束
            if (mScroller.computeScrollOffset()) {
                //调用view的滚动函数,进行实际滚动。
                scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
                //只有postInvalidate了才能循环刷新。
                postInvalidate();
            }    
            super.computeScroll();
        }
    }

    MainActivity.java:

    public class MainActivity extends Activity {
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            final CustomView view = new CustomView(this);
            setContentView(view);    
         //给button添加onClick监听 view.getChildAt(
    0).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub view.smoothScrollBy(0, -100); } }); } }

    参考网页:http://www.cnblogs.com/PDW-Android/p/3653253.html

    http://blog.csdn.net/gemmem/article/details/7321910

    http://www.open-open.com/lib/view/open1328834050046.html

  • 相关阅读:
    hdu 5101 Select
    hdu 5100 Chessboard
    cf B. I.O.U.
    cf C. Inna and Dima
    cf B. Inna and Nine
    cf C. Counting Kangaroos is Fun
    Radar Installation 贪心
    spfa模板
    Sequence
    棋盘问题
  • 原文地址:https://www.cnblogs.com/wliangde/p/3654948.html
Copyright © 2011-2022 走看看