android 布局之滑动探究 scrollTo 和 scrollBy 方法使用说明

涉及到滑动,就涉及到VIEW。大家都知道,android的UI界面都是由一个一个的View以及View的派生类组成。View作为基类,而经常使用的布局里面的各种布局就是它派生出来的ViewGroup的子类。ViewGroup作为各个组件的容器搭建了总体的UI。下面是android UI的结构示示意图:


查看源代码

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * Implement this to do your drawing. 
  3.  * 
  4.  * @param canvas the canvas on which the background will be drawn 
  5.  */  
  6. protected void onDraw(Canvas canvas) {  
  7. }  
能够发现。View的实现通常是通过绘制onDraw方法进行,假设你要改变它的界面能够重写onDraw。达到你的效果,在源代码中。你找不到    

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public void addView(View child) {  
  2.         addView(child, -1);  
  3.     }  
这种方法,由于它不知道。仅仅有在它的派生类比如ViewGroup中会有这个方式去加入子布局。

而ViewGroup作为一个组件容器,它能够包括不论什么组件,但是你必须重写他的onLayout() 方法和 onMeasure()来设置容器布局的位置和绘制它的大小才干正常显示。

首先 ,我们必须明确在Android View视图是没有边界的,Canvas是没有边界的,仅仅只是我们通过绘制特定的View时对 Canvas对象进行了一定的操作,比如 : translate(平移)、clipRect(剪切)等,以便达到我们的对该Canvas对象绘制的要求 ,我们能够将这样的无边界的视图称为“视图坐标”-----它不受物理屏幕限制。

通常我们所理解的一个Layout布局文件仅仅是该视图的显示区域,超过了这个显示区域将不能显示到父视图的区域中 ,相应的,我们能够将这样的有边界的视图称为“布局坐标”------ 父视图给子视图分配的布局(layout)大小。并且, 一个视图的在屏幕的起始坐标位于视图坐标起始处,例如以下图所看到的。


事实上是相对于父类视图的左上角坐标为原点(0。0),而不是总体ViewGroup的左上角为原点。

因为布局坐标仅仅能显示特定的一块内容,所以我们仅仅有移动布局坐标的坐标原点就能够将视图坐标的不论什么位置显示出来。

(注:比如cocos2D的布局就和android的布局坐标原点坐标不一样,是左下角会原点,所以会有所差异。


这里就大致提下View和ViewGroup。(网上非常多大神都对这块进行了分析,这里仅仅是做了少量摘抄记录)目的是为了引出今天的主角scrollTo 和 scrollBy。


查看下源代码能够发现:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <span style="font-family:SimSun;font-size:14px;">  /** 
  2.      * The offset, in pixels, by which the content of this view is scrolled 
  3.      * horizontally. 
  4.      * {@hide} 
  5.      */  
  6.     @ViewDebug.ExportedProperty(category = "scrolling")  
  7.     protected int mScrollX;  
  8.     /** 
  9.      * The offset, in pixels, by which the content of this view is scrolled 
  10.      * vertically. 
  11.      * {@hide} 
  12.      */  
  13.     @ViewDebug.ExportedProperty(category = "scrolling")  
  14.     protected int mScrollY;  
  15.     /** 
  16.      * Return the scrolled left position of this view. This is the left edge of 
  17.      * the displayed part of your view. You do not need to draw any pixels 
  18.      * farther left, since those are outside of the frame of your view on 
  19.      * screen. 
  20.      * 
  21.      * @return The left edge of the displayed part of your view, in pixels. 
  22.      */  
  23.     public final int getScrollX() {  
  24.         return mScrollX;  
  25.     }  
  26.   
  27.     /** 
  28.      * Return the scrolled top position of this view. This is the top edge of 
  29.      * the displayed part of your view. You do not need to draw any pixels above 
  30.      * it, since those are outside of the frame of your view on screen. 
  31.      * 
  32.      * @return The top edge of the displayed part of your view, in pixels. 
  33.      */  
  34.     public final int getScrollY() {  
  35.         return mScrollY;  
  36.     }</span>  

mScrollX:表示离视图起始位置的x水平方向的偏移量

mScrollY:表示离视图起始位置的y垂直方向的偏移量

分别通过getScrollX() 和getScrollY()方法获得。

注意:mScrollX和mScrollY指的并非坐标。而是偏移量。


[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <span style="font-family:SimSun;font-size:14px;"/** 
  2.      * Set the scrolled position of your view. This will cause a call to 
  3.      * {@link #onScrollChanged(int, int, int, int)} and the view will be 
  4.      * invalidated. 
  5.      * @param x the x position to scroll to 
  6.      * @param y the y position to scroll to 
  7.      */  
  8.     public void scrollTo(int x, int y) {  
  9.         if (mScrollX != x || mScrollY != y) {  
  10.             int oldX = mScrollX;  
  11.             int oldY = mScrollY;  
  12.             mScrollX = x;  
  13.             mScrollY = y;  
  14.             invalidateParentCaches();  
  15.             onScrollChanged(mScrollX, mScrollY, oldX, oldY);  
  16.             if (!awakenScrollBars()) {  
  17.                 postInvalidateOnAnimation();  
  18.             }  
  19.         }  
  20.     }  
  21.   
  22.     /** 
  23.      * Move the scrolled position of your view. This will cause a call to 
  24.      * {@link #onScrollChanged(int, int, int, int)} and the view will be 
  25.      * invalidated. 
  26.      * @param x the amount of pixels to scroll by horizontally 
  27.      * @param y the amount of pixels to scroll by vertically 
  28.      */  
  29.     public void scrollBy(int x, int y) {  
  30.         scrollTo(mScrollX + x, mScrollY + y);  
  31.     }</span>  

从以上的代码能够看出,scrollTo 和 scrollBy差别。事实上2者的效果是一样的。


scrollTo(int x,int y):

假设偏移位置发生了改变,就会给mScrollX和mScrollY赋新值,改变当前位置。

注意:x,y代表的不是坐标点。而是偏移量。

比如:

我要移动view到坐标点(100,100),那么我的偏移量就是(0,,0)  - (100,100) = (-100 ,-100)  ,我就要运行view.scrollTo(-100,-100),达到这个效果。


scrollBy(int x,int y):

从源代码中看出,它实际上是调用了scrollTo(mScrollX + x, mScrollY + y);

mScrollX + x和mScrollY + y,即表示在原先偏移的基础上在发生偏移,通俗的说就是相对我们当前位置偏移。

依据父类VIEW里面移动,假设移动到了超出的地方。就不会显示。

查看上文中的示意图你就会知道大概。



以下通过一个小样例了解下这2个方法之间的的使用,

效果图例如以下:


核心代码就是本文讲的2个方法,这里就列出代码了。

提供一个简单的DEMO:下载地址

这里大致搞清楚了这2个方法后,对后面的Scroller拖动类以及实现几个拖动效果就更加有帮助了。

原文地址:https://www.cnblogs.com/llguanli/p/6918198.html