OnLayout source code process logic (ANDROID custom view), onlayoutandroid
Reprint please indicate this article from the blog of the big glutinous rice (http://blog.csdn.net/a396901990), thank you for your support!
Introduction:
In the custom view, it is actually very simple. You only need to know the three steps:
1. Measurement -- onMeasure (): Determines the size of the View.
2. Layout -- onLayout ():Determine the position of the View in the ViewGroup
3. Draw -- onDraw ():How to draw this View.
The onDraw System in step 1 has been well encapsulated, so we don't have to worry about it. We just need to focus on Step 1 and step 2.
For the first measurement, refer to my previous article: (ANDROID custom view-onMeasure process, MeasureSpec)
This article will talk about Step 2.:"Layout)"
Knowledge Point Review:
Before talking about how to use the onLayout method, let's briefly recall the knowledge points:
View structure:
A View can be a single View, such as TextView or a View group such as LinearLayout.
For a View with multiple views, its structure is a tree structure, and the top layer is ViewGroup. There may be multiple viewgroups or views under ViewGroup.
The concept of this tree is very important, because when we measure the size or adjust the layout, we start from the top of the tree layer by layer, one branch and one branch (Tree Recursion).
A brief review of Measure:
Measure is used to calculate the actual value for the entire View tree.SizeAccording to the introduction to the View tree, if you want to calculate the size of the entire View tree, you need to recursively calculate the size of each subview (Layout is the same ).
Calculate the actual height (MMeasuredHeight) And width (MMeasureWidth) InputSetMeasuredDimension ()Method to complete the measurement of a single View. If the measured View is a ViewGroup, you can useMeasureChildRecursive calculation of each sub-view. The actual width and height of each View areParent ViewAndView.
Layout (source code analysis ):
Layout is used to calculate the actual value for the entire View tree.LocationAccording to the introduction to the View tree just now, to calculate the position of the entire View tree, we need to recursively calculate the position of each subview (the same is true for Measure ).
However, it is very easy to determine the location.MLeft, mTop, mRight, mBottomFour values (Note: These four values are the value of the Child View relative to the parent View, which will be described in detail below ).
How do I set these four values in the code?
First, whether LinearLayout provided by the system or our custom View, it must inherit from the ViewGroup class, you must rewrite the onLayout method (because onLayout is defined as an abstract method in ViewGroup ).
ViewGroup-onlayout:
@Overrideprotected abstract void onLayout(boolean changed, int l, int t, int r, int b);
OnLayout is defined as an abstract method. Therefore, you must override this method when inheriting ViewGroup (onMeasure is not required ). In addition, this method is also marked by override, so it is also a rewrite method, which overwrites the onLayout method in the view of its parent class.
View-onlayout:
/*** It is called by layout when the view and its subviews are assigned a size and location. * @ Param changed the size and position of the current View * @ param left (relative to parent View) * @ param top (relative to parent View) * @ param right (relative to parent view) * @ param bottom position (relative to parent view) */protected void onLayout (boolean changed, int left, int top, int right, int bottom ){}
Note: When this view and its subviews are assigned a size and location, it is called by layout. So let's see what is done in layout. (Annotations are not fully translated in English and are omitted)
View-layout:
/*** Allocate the size and position to the View and all its sub-views. ** this is the second stage of the layout (the first stage is measurement ). In this phase, each parent view needs to call layout to determine the position for all its child views * The derived subclass should not overwrite the layout method, and the onLayout method should be rewritten, in the onlayout method, you should call layout */public void layout (int l, int t, int r, int B) of each view) {// record the upper left and lower right of the current view as the old value (the new values include l, t, r, and B) int oldL = mLeft; int oldT = mTop; int oldB = mBottom; int oldR = mRight; // The setFrame method is used to assign the new ltrb attribute to the View, then, judge whether the current View size and position have changed and return boolean changed = setFrame (l, t, r, B); if (changed | (mPrivateFla Gs & PFLAG_LAYOUT_REQUIRED) = PFLAG_LAYOUT_REQUIRED) {// call the onLayout callback method. The specific implementation is implemented by the subclass of the ViewGroup that overwrites the onLayout method (described later) onLayout (changed, l, t, r, B); mPrivateFlags & = ~ PFLAG_LAYOUT_REQUIRED; // call all methods that overwrite the onLayoutChange listener to notify the View size and position of the ListenerInfo li = mListenerInfo; if (li! = Null & li. mOnLayoutChangeListeners! = Null) {ArrayList <OnLayoutChangeListener> listenersCopy = (ArrayList <OnLayoutChangeListener>) li. mOnLayoutChangeListeners. clone (); int numListeners = listenersCopy. size (); for (int I = 0; I <numListeners; ++ I) {listenersCopy. get (I ). onLayoutChange (this, l, t, r, B, oldL, oldT, oldR, oldB) ;}} mPrivateFlags & = ~ PFLAG_FORCE_LAYOUT ;}
In this Code, we only need to know that if the size and position of the view change, the onLayout method we analyzed previously will be called.
The final implementation of the onLayout method relies on the onLayout that we re-wrote in the Custom ViewGroup class.
Calculate View location:
In the override onLayout method, the only purpose is:
Set the specific positions of the current View and all its child views in the parent View (mLeft, mTop, mRight, and mBottom are used to determine the positions)
Previously, the values of mLeft, mTop, mRight, and mBottom indicate the position of the child view relative to the parent view. Below I will post the picture I have drawn to understand it.
The yellow area is our parent view, and the dark area in the middle is our child view.
So for this View, I will list how it calculates and related functions relative to the values of the parent view:
MLeft, mTop, mRight, mBottom:
View. getLeft () -- mLeft: the distance between the left boundary of the Child View and the left boundary of the parent view
public final int getLeft() { return mLeft; }
View. getTop () -- mTop: the distance between the upper boundary of the Child View and the upper boundary of the parent view
View. getRight () -- mRight: the distance between the right boundary of the Child View and the right boundary of the parent view
View. getBottom () -- mBottom: the distance from the bottom margin of the Child View to the bottom boundary of the parent View
View width and height:
View width View. getWidth (); right boundary of the sub-view-left boundary of the sub-view.
public final int getWidth() { return mRight - mLeft; }
View height View. getHeight (); subview bottom boundary-subview top boundary.
public final int getHeight() { return mBottom - mTop; }
Measurement width and height:
View. getMeasuredWidth (); mMeasuredWidth returned during the measure Process
public final int getMeasuredWidth() { return mMeasuredWidth & MEASURED_SIZE_MASK; }
View. getMeasuredHeight (); mMeasuredHeight returned during the measure Process
public final int getMeasuredHeight() { return mMeasuredHeight & MEASURED_SIZE_MASK; }
Finally, we will introduce the differences between getWidth/Height and getMeasuredWidth/Height:
GetWidth, getLeft, and other functions are the position of the View relative to its parent View. GetMeasuredWidth and getMeasuredHeight are the actual values of the View after measurement (a bit round. The following is an excerpt from the explanation in the Blog written by jafsldkfj ).
In fact, when the screen can wrap the content, their values are equal. Only when the view exceeds the screen can we see their difference:
GetMeasuredHeight () is the size of the actual View, regardless of the screen, while the size of getHeight is the size of the screen.
When the screen is exceeded, getMeasuredHeight () equals to getHeight () plus the size not displayed outside the screen
When calculating the position of a child View in the parent View, the above functions are mainly applied. Next let's take a look at how to rewrite onLayout.
OnLayout:
The idea of rewriting onLayout is the same as that of rewriting onMeasure:
If you only need to measure a single View, you just need to measure it independently. If there is a subview under the View to be measured, You need to measure all its subviews.
The preceding View is used as an example. The outermost View is a yellow parent View with a center deep lateral View in the middle. My idea is as follows: to draw a View, we need to calculate its l, t, r, and B values. And passed to onlayout (l, t, r, B); mRight = view. getWidth + mLeft; mBottom = view. getHeight + mTop; therefore, you can pass in the following form: onlayout (l, t, l + width, t + height );
The remaining tasks only need to know its mLeft value, mTop value, and the length and width value.
The length and width values are simple. You can use both getWidth/Height and getMeasuredWidth/Height.
Because the View needs to be centered, the remaining problem is how to calculate the mLeft value and mTop value of the View. My ideas are as follows:
R (mRight of the parent View) = mLeft + width + mLeft (because the left and right spacing is the same)
B (mBottom of the parent View) = mTop + height + mTop (because the spacing is the same)
My code is as follows:
@ Overrideprotected void onLayout (boolean changed, int l, int t, int r, int B) {// loop all sub-views for (int I = 0; I <getChildCount (); I ++) {View child = getChildAt (I); // retrieves the length and width of the current sub-View int width = child. getMeasuredWidth (); int height = child. getMeasuredHeight (); // calculate the current mLeft and mTop values (r, B is the mRight and mBottom values of the passed parent View) int mLeft = (r-width)/2; int mTop = (B-height)/2; // call layout and pass the calculated parameter to child view layout. layout (mLeft, mTop, mLeft + width, mTop + height );}}
The layout file is as follows:
<com.gxy.text.CostomViewGroup xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#eee999" > <Button android:text="ChildView" android:layout_width="200dip" android:layout_height="200dip" android:background="#333444" android:id="@+id/textView2" /></com.gxy.text.CostomViewGroup>
:
Summary:
OnMeasure and onLayout are roughly summarized. onLayout is the most important part in customizing a View. No matter how you Measure the size of this View, the final decision is always in the hands of onLayout, onLayout determines the size and position of a specific View. Of course, onMeasure is also very important. In complicated custom views, many calculations need to be completed in onMeasure, and some values will be recorded and reused in onLayout, please confirm ).
When writing onMeasure and onLayout, I just want to summarize it myself and sort out the ideas. Because there are too many records written on the internet, here we recommend the blog of qinjuning, the great god. He summarized the View content in a comprehensive and in-depth manner.
Although it is good, I will continue to summarize it myself. The next plan is to write a small example of a slightly complex point, combining onMeasure and onLayout. After that, I will thoroughly study the source code of the View and ViewGroup, summarize some simple common knowledge points such as LayoutParams and LayoutInflater, and learn about the drawing and refreshing process of the View... Too much. Come on.
Who calls the onlayout method?
This is the onlayout method in which it appears to be available in swing in java Development. It is used for window layout. I don't know which one you are!
Why is the onLayout method executed twice in the Custom View?
I just remember that when measure is used, the parent View will make each sub-View Measure its own size. If the parent View is too large or too small, it is not appropriate to ask the Sub-View to re-MeasureView. the MeasureSpec class seems to be related to the layout. view the original post>