Android Scroll (1): Basic knowledge
Android Scroll (1): Basic knowledge
In the front-end article, we have a general understanding of Android touch event processing and discussed in detailMotionEvent
. If you are not familiar with the knowledge in the previous article, please read Android MotionEvent details
Today, we will discuss the mechanism of UI scrolling effect in Android. This article mainly describes the knowledge points related to scrolling, and subsequent articles will involve actual code and principles. I hope you can understand or master the following knowledge after reading this article:
- Components of the Android View
mScrollX
AndmScrollY
Impact on View display
scrollTo
AndscrollBy
Use
invalidate
AndpostInvalidate
Difference
View's mScrollX and mScrollY
Everyone knows,View
There are two important member variables,mScrollX
,mScrollY
They represent the horizontal and vertical scrolling distance of the view content. We can usesetScrollX
AndsetScrollY
Function to change their values to scroll the content of the view.
It should be emphasized that,mScrollX
AndmScrollY
The view content changes, but does not affect the view background ).
I can see that the students may have questions. What is the difference between the View content and the background? What are the components of a view?
You can Viewdraw
The component of the View.
// http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/view/View.java#Viewpublic 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); ...... }
The lateral View content consists of the following parts:
- Background)
- Content)
- Subview
- Fade effect: the gradient effect may occur on the top, bottom, and left borders. The Code only shows the gradient effect of the upper and right borders.
- Border or decorative effect (decorations), such as a scroll bar
For example, we all know that in layout files,TextView
There are two important attributes:background
,text
.background
You can set the background of TextView, whiletext
Set the font content to be drawn.
mScrollX
AndmScrollY
The rendering of parts except the content itself has an impact. It does not affect the rendering of the view background.
Scroll direction
As we all know, in the Android view, layout-related values are all directional, suchmLeft
,mTop
.
As shown in the following figure, the coordinates of the Android view are located at the top-left corner of the screen. The positive direction of the X axis is right, and the positive direction of the Y axis is downward.
Then, when youmLeft
AndmTop
When the value is added to 10 and the view is re-painted, the view moves down to the right.
ThenmScrollY
AndmScrollX
Is it in such a coordinate domain? Their positive direction andmTop
AndmLeft
Is it the same? Yes, they belong to the same sitting area, with the same direction.
HowevermScrollX
AndmScrollY
And then callinvalidate()
If you re-draw the interface, you will find that the content in the view is moved to the upper left corner!
Why? In terms of concept, You can first solve the problem as follows:mScrollX
AndmScrollY
The change does not result in the movement of the View area.
The View area of lateral View is infinite. You canonDraw
Functioncanvas
But you will find that the final display on the screen is only a part, because the View itself also has the concept of size, that ismeasure
Andlayout
The view is configured with a length, width, and a position in the interface. In this way, the visible area of the view is determined.
NLP makes an image metaphor. The visible area of the View is a window on the wall. The View area of the View is equivalent to the beautiful scenery behind the wall. The scenery is wireless, but you can only see the scenery in the window. If the window grows and the outside scenery remains unchanged, you will see a larger view. If the window moves a distance to the bottom right corner, you will find that the outside scenery seems to be "moving" to the upper left corner.
ScrollTo and ScrollBy
These two functions are used to scroll the 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);}
When you look at the source code, you can easily understand the roles and differences of the two:scrollTo
Is to change directlymScrollX
AndmScrollY
AndscrollBy
IsmScrollX
AndmScrollY
Add the increment.
Invalidate and postInvalidate
The above two functions are the APIs that request the view to re-draw, but they differ in usage.
invalidate
Must be called in the main Thread (UI Thread), andpostInvalidate
It can be called in a Non-main Thread (Non-UI Thread.
In addition, there is a small difference between the two.
Callback callinvalidate
It checks whether the UI re-painting of the last request is complete. If it is not completed, it will do nothing.
Void invalidateInternal (int l, int t, int r, int B, boolean invalidateCache, boolean fullInvalidate ){..... // whether DRAWN and HAS_BOUNDS are set to 1 indicates that the UI painting of the last request has been completed. You can request to execute if (mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) again )) = (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) | (invalidateCache & (mPrivateFlags & signature) = signature) | (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: this is the subject of invalidate execution .....}}
WhilepostInvalidate
This is not the case. It sendsMessage
, And thenhandleMessage
, Calledinvalidate()
Function.
// View. java public void postInvalidateDelayed (long delayMilliseconds ){... attachInfo. mViewRootImpl. dispatchInvalidateDelayed (this, delayMilliseconds );...} // ViewRootImpl sends Message public void dispatchInvalidateDelayed (View view, long delayMilliseconds) {Message msg = mHandler. obtainMessage (MSG_INVALIDATE, view); mHandler. sendMessageDelayed (msg, delayMilliseconds);} // ViewRootImpl processes Messagepublic void handleMessage (Message msg) {switch (msg. what) {case MSG_INVALIDATE: (View) msg. obj ). invalidate (); break ;}}
Therefore, there is a difference in the call time between the two, such as the useScroller
For view scrolling, the two calls are different.
Follow-up
There will be two blog posts after the rollback, one is "detailed explanation of Android Scroll (II): overscroler practice" to explain the specific code implementation, and the other is "detailed explanation of Android Scroll (III ): the Android painting process details mainly refer to the scrolling Android Painting Process. Please pay more attention to it.