scrollTo 以及 scrollBy方法使用

在android开发中,很多地方都会遇到滑屏事件,如果不能很好的掌握android的滑屏事件,那么自己的开发能力将会很难进行提高。说实话,每次遇到滑屏事件里面的类对会很头疼,因为他们都很陌生~~~~所以自己更要迎难而上。

那么,为什么会出现这么多滑屏的事件呢?我们要明白在android view视图是没有边界的,canvas是无边界的。想想我们常用的ListView和GridView就知道了。我们平常可见的只是通过Layout布局来控制显示区域,超过了这个显示区域将不会进行显示。

又有问题了,我们怎么样把不显示的区域移动到显示的区域呢?而该布局只能显示一段特定的视图区域。从View.java类里的源码,我们会发现View类里面的scrollTo和scrollBy方法,这样就可以把不显示的区域的内容(注意不是View)坐标“滚动”到显示区域了。

既然有滚动,那么我们怎样获取它们的滚动值呢?
在View.java类源码中:

 /** * The offset, in pixels, by which the content of this view is scrolled * horizontally. * {@hide} */
    @ViewDebug.ExportedProperty(category = "scrolling")
    protected int mScrollX;
    /** * The offset, in pixels, by which the content of this view is scrolled * vertically. * {@hide} */
    @ViewDebug.ExportedProperty(category = "scrolling")
    protected int mScrollY;
 /**
     * Return the scrolled left position of this view. This is the left edge of
     * the displayed part of your view. You do not need to draw any pixels
     * farther left, since those are outside of the frame of your view on
     * screen.
     *
     * @return The left edge of the displayed part of your view, in pixels.
     */
    public final int getScrollX() {
 return mScrollX;
    }

    /**
     * Return the scrolled top position of this view. This is the top edge of
     * the displayed part of your view. You do not need to draw any pixels above
     * it, since those are outside of the frame of your view on screen.
     *
     * @return The top edge of the displayed part of your view, in pixels.
     */
    public final int getScrollY() {
 return mScrollY;
    }

首先,我们要认识mScrollX和mScrollY两个变量:

mScrollX: 该视图内容相当于视图起始坐标的偏移量, X轴方向
mScrollY: 该视图内容相当于视图起始坐标的偏移量, Y轴方向

它们的值分别通过getScrollX() 和getScrollY()方法获得。这样我们就可以 获得它们的滚动值了。

我们又怎么移动到指定地点呢?

在View.java中,

/** * Set the scrolled position of your view. This will cause a call to * {@link #onScrollChanged(int, int, int, int)} and the view will be * invalidated. * @param x the x position to scroll to * @param y the y position to scroll to */
    public void scrollTo(int x, int 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();
            }
        }
    }

从代码中,我们看出scrollTo()方法就是移动到指定的点。它首先判断这里移动的点是否和上次移动的偏移量一样,如果这次移动和上次移动的坐标是同一个,那么就没有必要进行移动了。

我们又怎么控制移动偏移量?

    /** * Move the scrolled position of your view. This will cause a call to * {@link #onScrollChanged(int, int, int, int)} and the view will be * invalidated. * @param x the amount of pixels to scroll by horizontally * @param y the amount of pixels to scroll by vertically */
    public void scrollBy(int x, int y) {
        scrollTo(mScrollX + x, mScrollY + y);
    }

我们可以看出它其实就是调用scrollTo方法,它只是将当前视图内容偏移偏移(x , y)个单位。

注意:
了解了这些机制后,我们再来看看移动问题。我们调用scrollTo(0,10)是不是就是像下偏移呢?不是的,它其实是向上偏移。这是为什么呢?
在scrollTo(x,y)中,x和y分别被赋值给了mScrollX和mScrollY,最后调用postInvalidateOnAnimation()方法。之后这个方法就会通知View进行重绘。在onDraw方法中我们可以看到第六步源码;

 if (!verticalEdges && !horizontalEdges) {
            // Step 3, draw the content
            if (!dirtyOpaque) onDraw(canvas);

            // Step 4, draw the children
            dispatchDraw(canvas);

            // Step 6, draw decorations (scrollbars)
            onDrawScrollBars(canvas);

            // we're done...
        }

它调用了onDrawScrollBars(canvas)方法。而scrollbars就是由于scroll引起的。而onDrawScrollBara(canvas)这个方法是绘制水平和垂直方向的ScrollBar,最后都会调用invalidate(left, top, right, bottom)方法。在invalidate(left, top, right, bottom)这个方法的最后,可以看到 tmpr.set(l - scrollX, t - scrollY, r - scrollX, b - scrollY),所以它就是反方法了。

那么我们怎么使用它们呢?

下面我们来写一个Demo来认识它(参考)。
我们先自定义一个ViewGroup的CusScrollView .java。

public class CusScrollView extends ViewGroup {
    private int lastX = 0;  //最后坐标
     private int currX = 0;  //当前坐标
     private int offX = 0; //相对偏移量
    public CusScrollView(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
    }

    /** * @param context * @param attrs */
    public CusScrollView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
        // TODO Auto-generated constructor stub
    }

    /** * @param context * @param attrs * @param defStyle */
    public CusScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        // TODO Auto-generated constructor stub

    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        // TODO Auto-generated method stub
        for(int i = 0 ; i < getChildCount();i++){
            View v = getChildAt(i);
            //横向布局
            v.layout(0+i*getWidth(), 0, getWidth()+i*getWidth(), getHeight());
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
             // 只考虑水平方向 
               lastX = (int) event.getX();  
               return true; 
        case MotionEvent.ACTION_MOVE:
             // 只考虑水平方向 
            currX = (int) event.getX(); 
            offX = currX - lastX;  
            scrollBy(-offX, 0); //相对向右滑动 
            break;
        case MotionEvent.ACTION_UP:  
               scrollTo(0, 0);  //回到起点
               break;  
        }
         invalidate();  
        // TODO Auto-generated method stub
        return super.onTouchEvent(event);
    }
}

然后我们在布局中使用自定义ViewGroup
activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    xmlns:tools="http://schemas.android.com/tools"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    android:orientation="vertical" >  

    <com.example.studyscrollto.CusScrollView  
        android:id="@+id/CusScrollView"  
        android:layout_width="match_parent"  
        android:layout_height="match_parent" >  

    </com.example.studyscrollto.CusScrollView>  

</LinearLayout> 

我们再来看MainActivity.java

public class MainActivity extends Activity {
     private int[] images = { R.drawable.guide_img1, R.drawable.guide_img2, R.drawable.guide_img3,  
                   R.drawable.guide_img4};  

    private CusScrollView mCusScrollView;  
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
         mCusScrollView = (CusScrollView) this.findViewById(R.id.CusScrollView);  
              for (int i = 0; i < images.length; i++) {  
                   ImageView mImageView = new ImageView(this);  
                   mImageView.setScaleType(ScaleType.FIT_XY);  
                   mImageView.setBackgroundResource(images[i]);  
                   mImageView.setLayoutParams(new LayoutParams(  
                             LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));  
                   mCusScrollView.addView(mImageView);  
              }  
    }


}

在上面的例子里,我们知道Layout的子控件就是ImageView,所以当我们滑动的时候,图片通过scrollBy会向右滑动,但是我们发现有一个问题,当我们滑动一下,非常快就回到了原点。有时候我们想他慢点滑动,那么我们怎么办呢?后面继续学习Scroller类。将会解决这个问题。
最后感谢这位博主给我学习这两个方法提供了平台。

你可能感兴趣的:(Android开发,scrollTo,ScrollBy)