編輯:關於Android編程
在前邊的文章中,我們已經對Android觸摸事件處理有了大致的了解,並且詳細探討了MotionEvent
的相關用法。對之前文章中的知識還不是很了解的同學,請閱讀《Android MotionEvent詳解》
今天,我們就來探討一下Android中界面滾動效果的相關機制,本篇文章主要講解一下滾動相關的知識點,之後的文章會涉及實際的代碼和原理。希望大家閱讀完這篇文章之後,能夠了解或者掌握一下知識:
mScrollX
和mScrollY
對視圖顯示的影響scrollTo
和scrollBy
的使用invalidate
和postInvalidate
的區別 我們都知道,View
中有兩個重要的成員變量,mScrollX
,mScrollY
.它們分別代表視圖內容(view content)水平方向和豎直方向的滾動距離。我們可以通過setScrollX
和setScrollY
來個函數來改變它們的值,從而來滾動視圖的內容。
在這裡需要強調的是,mScrollX
和mScrollY
會導致視圖內容(view content)變化,但是不會影響視圖背景(background)。
看到這裡同學們或許會有寫疑問,視圖的內容和背景有什麼區別呢?視圖還有哪些組成部分呢?
我們可以從View的draw
方法中得知View的組成部分。
// http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/view/View.java#View public void draw(Canvas canvas) { ........ /* * Draw traversal performs several drawing steps which must be executed * in the appropriate order: * * 1. Draw the background * 2. If necessary, save the canvas' layers to prepare for fading * 3. Draw view's content * 4. Draw children * 5. If necessary, draw the fading edges and restore layers * 6. Draw decorations (scrollbars for instance) */ // Step 1, draw the background, if needed if (!dirtyOpaque) { drawBackground(canvas); } ....... // Step 2, save the canvas' layers ....... // Step 3, draw the content if (!dirtyOpaque) onDraw(canvas); // Step 4, draw the children dispatchDraw(canvas); // Step 5, draw the fade effect and restore layers ....... if (drawTop) { matrix.setScale(1, fadeHeight * topFadeStrength); matrix.postTranslate(left, top); fade.setLocalMatrix(matrix); p.setShader(fade); canvas.drawRect(left, top, right, top + length, p); } ..... // Step 6, draw decorations (scrollbars) onDrawScrollBars(canvas); ...... }
View顯示內容由一下幾個部分組成:
舉個例子吧,我們都知道在布局文件中,TextView
有兩個比較重要的屬性:background
,text
。background
可以設置TextView的背景,而text
則是設置要繪制字體內容。
mScrollX
和mScrollY
對除了本身內容外的部分的繪制都有影響。只是不會影響視圖背景的繪制。
我們都知道,在Android的視圖中,布局相關的數值都是有方向性的,比如mLeft
,mTop
。
由上圖我們可以知道,Android視圖坐標的原點在屏幕的左上方,x軸正方向是向右,y軸正方向是向下。
所以,當你將mLeft
和mTop
的數值加10並且重繪視圖時,視圖會向右下移動。
那麼mScrollY
和mScrollX
也在這樣一個坐標域中嗎?它們的正方向和mTop
和mLeft
是一樣的嗎?是的,它們屬於同一個坐標域,方向性相同。
但是如果你將mScrollX
和mScrollY
的數值都增大10,然後調用invalidate()
重新繪制界面的話,你會發現視圖中的內容都向左上角移動啦!
這是怎麼回事呢?從概念上你可以先這樣解:mScrollX
和mScrollY
改變導致View的可視區域的移動,並不是導致View的視圖區域的移動。
View的視圖區域相當於無限大的,你可以在onDraw
函數中的canvas
中繪制任意大的圖像,但是你會發現,最終屏幕上顯示出來的只會是一部分,因為View自身還有大小概念,也就是measure
和layout
時,視圖會被設置長寬還有界面中位置,這樣的話,視圖可視區域就被確定啦。
做一個形象的比喻。View的可視區域就是一面牆上的窗戶,View的視圖區域就相當於牆後邊的優美景色。牆外風光無線,但是你只能看到窗戶中的景色。如果窗戶變大啦,外邊風景不變,你看到的景色就大了一點;如果窗戶向右下角移動了一段距離,你就會發現外邊的景色好像是向左上角”移動”了一段距離。
這兩個函數是用來滾動視圖的API
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(); } } } public void scrollBy(int x, int y) { scrollTo(mScrollX + x, mScrollY + y); }
大家看源代碼很容易就理解了二者的作用和區別:scrollTo
就是直接改變mScrollX
和mScrollY
;而scrollBy
則是給mScrollX
和mScrollY
加上增量。
上邊這兩個函數都是請求視圖重新繪制的API,但是二者的使用有些區別。
invalidate
必須在主線程(UI Thread)中調用,而postInvalidate
可以在非主線程(Non UI Thread)中調用。
除此之外,二者還有點小區別。
調用invalidate
時,它會檢查上一次請求的UI重繪是否完成,如果沒有完成的話,那麼它就什麼都不做。
void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, boolean fullInvalidate) { ..... //DRAWN和HAS_BOUNDS是否被設置為1,說明上一次請求執行的UI繪制已經完成,那麼可以再次請求執行 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED || (fullInvalidate && isOpaque() != mLastIsOpaque)) { ...... final AttachInfo ai = mAttachInfo; final ViewParent p = mParent; final Rect damage = ai.mTmpInvalRect; damage.set(l, t, r, b); p.invalidateChild(this, damage);//TODO:這是invalidate執行的主體 ..... } }
而postInvalidate
則不會這樣,它是向主線程發送個Message
,然後handleMessage
時,調用了invalidate()
函數。
所以,二者的調用時機還是有區別的,就比如使用Scroller
進行視圖滾動時,二者的調用就有所不同。
之後還有會兩篇博文,一篇是《Android Scroll詳解(二):OverScroller實戰》講解具體代碼實現,另外一篇是《Android Scroll詳解(三):Android 繪制過程詳解》主要是從滾動角度理解Android繪制過程,請大家多多關注啊。
瞬時數據是指那些存儲在內存當中,有可能會因為程序關閉或其他原因導致內存被回收而丟失的數據。這對於一些關鍵性的數據信息來說是絕對不能容忍的,誰都不希望自己剛發出去的一條微博
先看看效果:實現代碼:public class ScrollBanner extends LinearLayout { private TextView mBanner
在Activity,Service,Window中監聽Home鍵和返回鍵的一些思考,如何把事件傳遞出來的做法! 其實像按鍵的監聽,我相信很多人都很熟練了,我肯定也不會說這
上面一篇博客,介紹了Studio的優點與1.0 RC的安裝與上手體驗,沒想到google的更新速度這麼快,已經出了RC 2版本,主要是修復一些bug。那麼今天就帶大家預覽