android中所有View都是可以滑动的,其实所有的View都有两套坐标系,一个是指定View位置的X,Y,另一对则是指定View滑动坐标系,mScrollX和mScrollY,两对坐标系统是完全独立的,即X,Y坐标的改变不会影响mScrollX和mScrollY,反之也成立。
scrollTo(int x, int y) 是将View中内容滑动到相应的位置,参考的坐标系原点为parent View的左上角。
mScrollX和mScrollY是View类中专门用于记录滑动位置的变量。这两个函数最终调用onScrollChanged()函数。
android的滑动原理就是:通过调用scrollTo(),使的View的滑动坐标系发生改变,并保存在mScrollX和mScrollY这两个成员变量中,我们可以通过getScrollX()和getScrollY(),获取滑动坐标值。
当我们调用scrollTo(100,0);时,发现View是向左滑动了,传入一个正数滑动的方向却是向左,这与我们平常理解的坐标轴是相反的,其实并不矛盾,因为滑动坐标系本来就与我们平常的坐标系统不一样,调用scrollTo方法,最终会执行到以下代码:
1. public void invalidate(int l, int t, int r, int b) {
2. if (ViewDebug.TRACE_HIERARCHY) {
3. ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE);
4. }
5.
6. if (skipInvalidate()) {
7. return;
8. }
9. if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS) ||
10. (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID ||
11. (mPrivateFlags & INVALIDATED) != INVALIDATED) {
12. mPrivateFlags &= ~DRAWING_CACHE_VALID;
13. mPrivateFlags |= INVALIDATED;
14. mPrivateFlags |= DIRTY;
15. final ViewParent p = mParent;
16. final AttachInfo ai = mAttachInfo;
17. //noinspection PointlessBooleanExpression,ConstantConditions
18. if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
19. if (p != null && ai != null && ai.mHardwareAccelerated) {
20. // fast-track for GL-enabled applications; just invalidate the whole hierarchy
21. // with a null dirty rect, which tells the ViewAncestor to redraw everything
22. p.invalidateChild(this, null);
23. return;
24. }
25. }
26. if (p != null && ai != null && l < r && t < b) {
27. final int scrollX = mScrollX;
28. final int scrollY = mScrollY;
29. final Rect tmpr = ai.mTmpInvalRect;
30. tmpr.set(l - scrollX, t - scrollY, r - scrollX, b - scrollY);
31. p.invalidateChild(this, tmpr);
32. }
33. }
34. }
看倒数第五行代码,更新滑动坐标系时,走的是 tmpr.set(l - scrollX, t - scrollY, r - scrollX, b - scrollY);传入一个正数后一减,就成了负数,然后就成了向左移动了;View中的滑动都是瞬时滑动。没有任何的过渡效果.