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

  • 相关阅读:
    Codeup
    IDEA基于Maven Struts2搭建配置及示例
    深入理解HTTP协议、HTTP协议原理分析
    25条提高iOS App性能的技巧和诀窍
    怎么在苹果Mac虚拟机上安装Win7
    app让个别界面横屏,其他的为竖屏,解决如下
    设置控制器,出现默认知道空隙
    论项目采购管理
    hybrid app
    iOS中使用 Reachability 检测网络
  • 原文地址:https://www.cnblogs.com/wliangde/p/3654948.html
Copyright © 2011-2022 走看看