Android开发中,在自定义控件的时候,如果涉及到滑动事件,经常需要使用View提供的诸如scrollTo()、scrollBy()、getScrollX()、getScrollY()等方法。但在这些api的实际使用过程中,开发人员很容易在移动方向、移动距离上产生迷惑,本文通过图例总结了这四种方法的区别和联系。
在讲解之前,首先需要明白的一点时,在Android手机屏幕坐标系中,坐标原点(0, 0)位于左上角,X轴方向向右为正方向,但Y轴方向与“笛卡尔”坐标系中的Y轴方向相反,即向下为Y轴正方向。
同理,View相对于它的父容器ParentView的相对位置的坐标变化方向也是与上图坐标系方向一致的。下面是亦枫列举的关于scrollTo()、scrollBy()、getScrollX()和getScrollY()的一些知识点和容易混淆的地方。为了更好地讲述,先贴上源码:
/**
* 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()) {
invalidate(true);
}
}
}
/**
* 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);
}
/**
* 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;
}
滑动对象
scrollTo和scrollBy用于滑动View的内容,而不是改变View本身所处的位置。所以,单独的View滑动很少见,更多的是ViewGroup调用scroll方法滑动子控件的位置。比如,使用TextView对象调用scrollTo或者ScrollBy方法,会发现TextView里面的文本内容的位置发生改变,而TextView本身所处的位置没有变化。getScrollX()和getScrollY()
返回值mScrollX和mScrollY分别表示距离起始位置的X轴或Y轴方向上的偏移量,而不是View在X轴或Y轴方向上的坐标值,用于记录偏移增量的两个变量。所以,mScrollX和mScrollY的初始值为0和0。scrollTo(int x, int y)
从源码中可以看出,scrollTo移动的目标位置x和y值是以初始化的mScrollX和mScrollY为参考点的,只要位置发生偏移,就对mScrollX和mScrollY赋新值。注意,这里的(x,y)理解为针对初始化值的偏移量,比如,我想移动到(100,100)这个位置,那么偏移量就是(0,0)-(100,100)=(-100,100),所以调用的时候就是view.scrollTo(-100, -100),这样才能达到我们想要的偏移效果。scrollBy(int x, int y)
从源码中可以看到,scrollBy依旧调用了scrollTo方法:scrollTo(mScrollX + x, mScrollY + y),只是参考点不再是初始化时的(0,0),相对于当前位置的偏移量。
最后,通过图例来说明上述所讲的内容。
初始化视图(为了展示效果,此处故意将子View和父View大小岔开):
以scrollTo的正负值移动为例来说明移动方向:
scrollBy(int x,int y)在正负值的移动方向和scrollBy一致,这里就不重复列举了。
欢迎欢迎关注作者微信公众号:技术鸟,一起学习,共同进步。