Reprint Please specify source: http://blog.csdn.net/singwhatiwanna/article/details/38426471 (from Singwhatiwanna's CSDN blog)
Android View System Parsing series:
Android View system resolution (top)
Introduction to view basics, view sliding, elastic sliding, sliding conflict resolution, event distribution, and more
Android View System parsing (bottom)
Introduces the framework layer principle of view, the Measure/layout/draw three processes of view and some advanced techniques
This main introduction of the second half, the outline is as follows
The drawing process of view
Measure/layout/draw Work Flow
Identify Measurespec and make the right Measurespec
Get the View's wide height before rendering
Construct a special View
Custom View
Custom View Categories
customizing View Notes
the drawing process of a view
first knowledge of Viewroot
Viewroot
Corresponds to the Viewrootimpl class, which is the link between WindowManager and Decorview.
Activitythread when the activity object is created, the Decorview is added to the window to complete the Viewrootimpl creation and Decorview connection.
root = new Viewrootimpl (View.getcontext (), display);
Root.setview (view, Wparams, Panelparentview);
The drawing process for view starts with the Viewroot performtraversals, which is the code flow:
Performmeasure, Measure, onmeasure
PerformLayout, Layout, onlayout
Performdraw, Draw, OnDraw
composition of the activity interface
From the Decorview as a top view, generally it has the upper and lower parts (the case will be related to the API version and theme), above is the title, the following is the content, In the activity we call the view set by Setcontentview is actually added to the content, and how to get content, you can: ViewGroup group = Findviewbyid ( r.android.id.content), how to get the view we set, can be like this: Group.getchildat (0). At the same time, through the source code we can know, Decorview is actually a framelayout. One point to note here is that most of the events in the view layer are passed from Decorview to our view.
Measurespec
Measurespec
Encapsulates the parent container's restrictions on the layout of the view, providing a wide range of information (Specmode, specsize), specsize refers to the reference size under a certain specmode, where Specmode has the following three kinds:
UNSPECIFIED
Parent container does not have any restrictions on view, how big
Exactly
The parent container has detected the size required for the view
At_most
The parent container specifies a size that cannot be greater than the size of the view
The meaning of Measurespecs
By packaging Specmode and specsize into an int value to avoid excessive object memory allocation, it provides a package/Jie Baofang method for ease of operation
the realization of Measurespec
Measurespec
Represents a 32-bit int value
High 2-bit stands for specmode, low 30-bit for specsize
Let's take a look at the definitions of some constants inside Measurespec, and it's not difficult to understand how MEASURESPEC works with the code below.
private static final int mode_shift = 30;private static final int mode_mask = 0x3 << mode_shift;public static final int UNSPECIFIED = 0 << mode_shift;public static final int exactly = 1 << mode_shift;public static final int at _most = 2 << mode_shift;public static int makemeasurespec (int size, int MODE) {if (Susebrokenmakemeasurespec) {retur n size + mode;} else {return (size & ~mode_mask) | (Mode & Mode_mask);}} public static int GetMode (int measurespec) {return (Measurespec & Mode_mask);} public static int GetSize (int measurespec) {return (Measurespec & ~mode_mask);}
Measurespec and LayoutparamsFor Decorview, its measurespec is determined by the size of the window and its own layoutparams.
For application-layer View, its measurespec is determined by the measurespec of the parent container and its own layoutparams.
Measurespec once determined, the onmeasure can determine its own width and height
Measurespec-decorview
The measurespec of the top container Decorview is analyzed here.
Childwidthmeasurespec = Getrootmeasurespec (basesize, lp.width);
Childheightmeasurespec = Getrootmeasurespec (Desiredwindowheight, lp.height);
Performmeasure (Childwidthmeasurespec, Childheightmeasurespec);
The above code describes the process of Decorview's measurespec, and in order to understand it more clearly, we continue to see
private static int Getrootmeasurespec (int windowsize, int rootdimension) {int Measurespec;switch (rootdimension) { Case ViewGroup.LayoutParams.MATCH_PARENT: //Window can ' t resize. Force root view to be windowsize. Measurespec = Measurespec.makemeasurespec (windowsize, measurespec.exactly); Break;case ViewGroup.LayoutParams.WRAP_CONTENT: //Window can resize. Set max size for root view. Measurespec = Measurespec.makemeasurespec (windowsize, measurespec.at_most); Break;default: //Window wants to is an exact size. Force root view to is that size. Measurespec = Measurespec.makemeasurespec (rootdimension, measurespec.exactly); break;} return measurespec;}
Through the above code, the Measurespec of the top-level container Decorview is very clear, in particular, it follows the following rules:
According to the width and height parameters of the Layoutparams,
layoutparams.match_parent: Its mode is exact mode, size is the size of the window
layoutparams.wrap_content: Its mode is the maximum mode, the size is variable, but cannot exceed the size of the window
fixed size (e.g. 100DP): its mode is exact mode, size is the size specified in Layoutparams
measurespec-Application Layer ViewFor application layer view, here is the view in our layout, whose measurespec is created following the rules in the following table
For the above table, here is a detailed explanation. As mentioned earlier, for application-layer View, its measurespec by the parent container's measurespec and self-
The layoutparams of the body, the layoutparams,view of different parent containers and view itself can have a variety of measurespec. This is simply to say, when the view uses a fixed width height, regardless of the parent container's measurespec, the view measurespec is the exact mode and its size follows the size of the layoutparams, when the view's width is Match_ Parent, this time if the parent container's pattern is precision mode, then view is also precision mode and its size is the remaining space of the parent container, if the parent container is the largest mode, then view is the largest mode and its size does not exceed the remaining space of the parent container; When the width of the view is WRAP_ Content, the view mode is always maximized and cannot exceed the remaining space of the parent container, regardless of whether the parent container's pattern is accurate or maximized. You may find that in our analysis we have omitted the unspecified mode, which is mainly used in the case of multiple measure within the system, in general, we do not need to pay attention to this pattern.
support for View wrap_content
Default implementation of View#onmeasure
protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {
Setmeasureddimension (Getdefaultsize (Getsuggestedminimumwidth (),
WIDTHMEASURESPEC), Getdefaultsize (Getsuggestedminimumheight (), heightmeasurespec));
}
Attention:
With OnDraw-derived View, you need to override the Onmeasure and set the Wrap_content self-
Body size, otherwise using wrap_content is equivalent to using Match_parent.
Cause analysis: see the table above
So how do you rewrite onmeasure so that view supports wrap_content? See the typical code below to note that Mwidth and mheight in the code refer to the internal specifications of the view under Wrap_content, which should be specified by the custom view interior.
protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {super.onmeasure (Widthmeasurespec, HEIGHTMEASURESPEC); int widthspecmode = Measurespec.getmode (widthmeasurespec); int widthspecsize = MeasureSpec.getSize (widthmeasurespec); int heightspecmode = Measurespec.getmode (heightmeasurespec); int heightspecsize = Measurespec.getsize (HEIGHTMEASURESPEC); if (Widthspecmode = = Measurespec.at_most && Heightspecmode = = Measurespec.at_most) {setmeasureddimension (mwidth, mheight);} else if (Widthspecmode = = Measurespec.at_most) { Setmeasureddimension (Mwidth, heightspecsize);} else if (Heightspecmode = = measurespec.at_most) {setmeasureddimension (widthspecsize, mheight);}}
measure process for view
measure process for view
Simple, Direct completion
ViewGroup's measure process
In addition to the completion of their own measure, will also traverse to call all child measure method, each child and then recursion to execute the process
Direct results of measure:
Getmeasuredwidth/height can be correctly obtained to
Note: In some cases, the system may require multiple measure to determine the size
get the View's wide height before rendering
This is a more meaningful question, or a difficult question, with the background: sometimes we need to get its width in view rendering, typically we want to get the width of the view in OnCreate, OnStart, Onresume. If you have tried, you will find that this time the view is not measure good, the width of the high is 0, that exactly what to do to correctly obtain its width, the following three ways
activity/view#onwindowfocuschanged : This method shows that the View has been initialized, and the width is ready.
view.post (runnable) : A runnable can be posted to the end of the message queue by post, and then the view is initialized when Looper calls this runnable
view.measure (int widthmeasurespec, int heightmeasurespec) : View width is obtained by manually going to measure
The first two methods are relatively good to understand and relatively simple, here is the main introduction of the next third method of detailed usage:
Use View.measure to get the width of the view in advance, according to the view of the layoutparams to divide
Match_parent
Directly give up, can not measure out the specific width of the high
Specific values (DP/PX)
For example, the width and height are 100px, the following measure:
int widthmeasurespec = Measurespec.makemeasurespec (+, measurespec.exactly);
int heightmeasurespec = Measurespec.makemeasurespec (+, measurespec.exactly);
View.measure (Widthmeasurespec, Heightmeasurespec);
Wrap_content
The following measure:
int widthmeasurespec = Measurespec.makemeasurespec ((1 <<)-1, measurespec.at_most);
int heightmeasurespec = Measurespec.makemeasurespec ((1 <<)-1, measurespec.at_most);
View.measure (Widthmeasurespec, Heightmeasurespec);
Note (1 << 30)-1, by analyzing the implementation of the MEASURESPEC can be known that the size of the view using 30-bit binary representation, that is, the maximum is 30 1 is 2^30-1, that is (1 << 30)-1, in the maximized mode, we use The maximum value that view can theoretically support to construct measurespec is reasonable.
On the measure of the view, there are two wrong usages on the network, such as, why is wrong, first violate the system's internal implementation specification (because cannot pass the wrong measurespec to obtain the legal Specmode thus causes measure error), Second, there is no guarantee that the correct results will be measure.
The first type of error usage
int widthmeasurespec = Measurespec.makemeasurespec ( -1, measurespec.unspecified);
int heightmeasurespec = Measurespec.makemeasurespec ( -1, measurespec.unspecified);
View.measure (Widthmeasurespec, Heightmeasurespec);
The second type of error usage
View.measure (Layoutparams.wrap_content, layoutparams.wrap_content)
the layout process of the View
The main function of layout
The ViewGroup is used to determine the position of the child element.
Process
When the position of the viewgroup is determined, it will traverse all the child in OnLayout and call its layout. OnLayout will be called in layout.
Key methods
public void layout (int l, int t, int r, int b)
OnLayout (changed, L, T, R, B)
construct a special View
question : How do I make getwidth and getmeasuredwidth return a different value?
private void Setchildframe (View child, int left, int top, int measuredwidth, int measureheight) {
Child.layout (left, top, left + measuredwidth, top + measureheight);
}
int width = Right-left;
int height = Bottom-top
Method
Place the view anywhere in the onlayout of the parent container by Child.layout
Modify the Mleft/mright/mtop/mbottom in your own onlayout
the draw process for View
The approximate flow of draw
A. painting background background.draw (canvas)
B. Draw yourself (OnDraw)
C. drawing children (Dispatchdraw)
D. drawing decorations (Ondrawscrollbars)
Note:
Dispatchdraw will iterate through the draw that calls all child, so the draw event is passed down one layer at a
two custom View
Custom View Type
Inherit View rewrite OnDraw
Inherit ViewGroup to derive specific Layout
Inherit a specific View (e.g. TextView, ListView)
Inherit specific Layout (e.g. LinearLayout)
Customizing View notesLet view support Wrap_content
If necessary, let your view support padding
Try not to use Handler in view, no need
If the thread or animation in the view needs to be stopped in time, refer to View#ondetachedfromwindow
When a view has a sliding nesting situation, it needs to handle the sliding conflict.
More InformationHttp://blog.csdn.net/singwhatiwanna
Https://github.com/singwhatiwanna