3.2 View的滑动
3.1节介绍了 View 的一些基础知识和概念,本节开始介绍很重要的一个内容:View的滑动。在Android设备上,滑动几乎是应用的标配,不管是下拉刷新还是 SlidingMenu,它们的基础都是滑动。从另外一方面来说,Android手机由于屏幕比较小,为了给用户呈现更多的内容,就需要使用滑动来隐藏和显示一些内容。
基于上述两点,可以知道,滑动在 Android开发中具有很重要的作用,不管一些滑动效果多么绚丽,归根结底,它们都是由不同的滑动外加一些特效所组成的。因此,掌握滑动的方法是实现绚丽的自定义控件的基础。
通过三种方式可以实现View的滑动:
第一种是通过 View 本身提供的 scrollTo/scrollBy 方法来实现滑动;
第二种是通过动画给 View 施加平移效果来实现滑动;
第三种是通过改变 View 的 LayoutParams 使得 View 重新布局从而实现滑动。
从目前来看,常见的滑动方式就这么三种,下面一一进行分析。
3.2.1 使用 scrollTo/scrollBy
为了实现 View 的滑动,View 提供了专门的方法来实现这个功能,那就是 scrollTo 和 scrollBy,我们先来看看这两个方法的实现,如下所示。
/**
* 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();
}
}
}
/**
* 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);
}
从上面的源码可以看出,scrollBy 实际上也是调用了 scrollTo 方法,它实现了基于当前位置的相对滑动,而 scrollTo 则实现了基于所传递参数的绝对滑动,这个不难理解。利用 scrollTo 和 scrollBy 来实现 View的 滑动,这不是一件困难的事,但是我们要明白滑动过程中 View内部的两个属性 mScrollX 和 mScrollY 的改变规则,这两个属性可以通过 getScrollX 和 getScrollY 方法分别得到。
这里先简要概况一下:在滑动过程中,mScrollX 的值总是等于 View 左边缘和 View 内容左边缘在水平方向的距离,而 mScrollY 的值总是等于 View 上边缘和 View 内容上边缘在竖直方向的距离。View 边缘是指 View 的位置,由四个顶点组成,而 View 内容边缘是指 View 中的内容的边缘,scrollTo 和 scrollBy 只能改变 View 内容的位置而不能改变 View 在布局中的位置。
mScrollX 和 mScrollY 的单位为像素,并且当 View 左边缘在 View 内容左边缘的右边时,mScrollX为正值,反之为负值;当 View 上边缘在 View 内容上边缘的下边时,mScrollY为正值,反之为负值。换句话说,如果从左向右滑动,那么 mScrollX 为负值,反之为正值;如果从上往下滑动,那么 mScrollY 为负值,反之为正值。
为了更好地理解这个问题,下面举个例子,如图3-3所示。在图中假设水平和竖直方向的滑动距离都为 100 像素,针对图中各种滑动情况,都给出了对应的 mScrollX 和 mScrollY 的值。根据上面的分析,可以知道,使用 scrollTo 和 scrollBy 来实现 View 的滑动,只能将 View 的内容进行移动,并不能将View本身进行移动,也就是说,不管怎么滑动,也不可能将当前 View 滑动到附近 View 所在的区域,这个需要仔细体会一下。
图3-3 mScrollX 和 mScrollY 的变换规律示意