涉及到滑動,就涉及到VIEW。大家都知道,android的UI界面都是由一個一個的View以及View的派生類組成。View作為基類,而經常使用的布局里面的各種布局就是它派生出來的ViewGroup的子類。ViewGroup作為各個組件的容器搭建了總體的UI。下面是android UI的結構示示意圖:
查看源代碼
- /**
- * Implement this to do your drawing.
- *
- * @param canvas the canvas on which the background will be drawn
- */
- protected void onDraw(Canvas canvas) {
- }
- public void addView(View child) {
- addView(child, -1);
- }
而ViewGroup作為一個組件容器,它能夠包括不論什么組件,但是你必須重寫他的onLayout() 方法和 onMeasure()來設置容器布局的位置和繪制它的大小才干正常顯示。
首先 ,我們必須明確在Android View視圖是沒有邊界的,Canvas是沒有邊界的,僅僅只是我們通過繪制特定的View時對 Canvas對象進行了一定的操作,比如 : translate(平移)、clipRect(剪切)等,以便達到我們的對該Canvas對象繪制的要求 ,我們能夠將這樣的無邊界的視圖稱為“視圖坐標”-----它不受物理屏幕限制。
通常我們所理解的一個Layout布局文件僅僅是該視圖的顯示區域,超過了這個顯示區域將不能顯示到父視圖的區域中 ,相應的,我們能夠將這樣的有邊界的視圖稱為“布局坐標”------ 父視圖給子視圖分配的布局(layout)大小。並且, 一個視圖的在屏幕的起始坐標位於視圖坐標起始處,例如以下圖所看到的。
事實上是相對於父類視圖的左上角坐標為原點(0。0),而不是總體ViewGroup的左上角為原點。
因為布局坐標僅僅能顯示特定的一塊內容,所以我們僅僅有移動布局坐標的坐標原點就能夠將視圖坐標的不論什么位置顯示出來。
(注:比如cocos2D的布局就和android的布局坐標原點坐標不一樣,是左下角會原點,所以會有所差異。
)
這里就大致提下View和ViewGroup。(網上非常多大神都對這塊進行了分析,這里僅僅是做了少量摘抄記錄)目的是為了引出今天的主角scrollTo 和 scrollBy。
- <span style="font-family:SimSun;font-size:14px;"> /**
- * 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;
- }</span>
mScrollX:表示離視圖起始位置的x水平方向的偏移量
mScrollY:表示離視圖起始位置的y垂直方向的偏移量
分別通過getScrollX() 和getScrollY()方法獲得。
注意:mScrollX和mScrollY指的並非坐標。而是偏移量。
- <span style="font-family:SimSun;font-size:14px;"> /**
- * 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);
- }</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拖動類以及實現幾個拖動效果就更加有幫助了。