In the previous article we learned about view onmeasure, so today we continue to learn the second step of the Android View Drawing trilogy, OnLayout, layout.
Viewrootimpl#performlayout
private void PerformLayout (windowmanager.layoutparams LP, int desiredwindowwidth, int desiredwindowheight) { mlayoutrequested = false; Mscrollmaychange = true; Minlayout = true;
Final View host = MView; if (Debug_orientation | | Debug_layout) { LOG.V (Mtag, ' laying out ' + Host + ' to (' + host.getmeasure Dwidth () + "," + host.getmeasuredheight () + ")"); Trace.tracebegin (Trace.trace_tag_view," Layout "); Host.layout (0, 0, host.getmeasuredwidth (), Host.getmeasuredheight ()); //The code omitted here is in the process of layout, the repetitive requestlayout that need to be handled. //The specific treatment scheme is to re-measure,layout. ... Trace.traceend (Trace.trace_tag_view); /span> |
The main function of this method is to call the Host.layout, and the already well-mapped wide-height transmission calculation into the upper and lower left and right hand over, host is Decorview.
View#layout
public void layout (int l, int t, int r, int b) { According to the MPRIVATEFLAGS3 mark bit status, if necessary, re-measure. if ((MPRIVATEFLAGS3 & pflag3_measure_needed_before_layout)! = 0) { Onmeasure (Moldwidthmeasurespec, Moldheightmeasurespec); MPRIVATEFLAGS3 &= ~pflag3_measure_needed_before_layout; }
int OLDL = Mleft; int Oldt = Mtop; int oldb = Mbottom; int oldr = Mright; Check that there is a change in position and Setframe Setframe analysis See below Boolean changed = Islayoutmodeoptical (mparent)? Setopticalframe (L, T, R, B): Setframe (L, T, R, b); OnLayout if the position is changed or if the pflag_layout_required mark bit is on if (changed | | (Mprivateflags & pflag_layout_required) = = pflag_layout_required) { OnLayout (changed, L, T, R, b); Put the pflag_layout_required mark position off Mprivateflags &= ~pflag_layout_required; Make a Onlayoutchange callback Listenerinfo li = mlistenerinfo; if (Li! = null && li.monlayoutchangelisteners! = null) { arraylist<onlayoutchangelistener> listenerscopy = (arraylist< onlayoutchangelistener>) Li.mOnLayoutChangeListeners.clone (); int numlisteners = Listenerscopy.size (); Listenerscopy.get (i). Onlayoutchang E (this, L, T, R, B, Oldl, Oldt, Oldr, OLDB); Mprivateflags &= ~pflag_ Force_layout; MPrivateFlags3 |= pflag3_is_laid_out; /span> |
View#setframe
protected Boolean setframe (int left, int top, int. right, int bottom) { Boolean changed = FALSE;
if (DBG) { LOG.D ("View", this + "View.setframe" ("+ Left +", "+ Top +", " + Right + "," + Bottom + ")"; } If there is any change in the upper and lower left or right, continue down or return false if (mleft! = left | | Mright! = RIGHT | | Mtop! = TOP | | Mbottom! = bottom) { changed = TRUE;
Record the status of the Pflag_drawn, the last time you need to restore int drawn = mprivateflags & pflag_drawn;
int oldwidth = Mright-mleft; int oldheight = Mbottom-mtop; int newwidth = Right-left; int newheight = Bottom-top; Boolean sizeChanged = (newwidth! = oldwidth) | | (Newheight! = oldheight);
Refresh the original layout, and the Invalidate method will expand in detail in another article. Invalidate (sizeChanged);
Setting the view up or down, is also the core function of Setframe Mleft = left; Mtop = top; Mright = right; Mbottom = bottom; Mrendernode.setlefttoprightbottom (Mleft, Mtop, Mright, Mbottom); Pflag_has_bounds position is on Mprivateflags |= pflag_has_bounds;
If the dimensions are changed, call Onsizechange and call Rebuildoutline if (sizeChanged) { Sizechange (Newwidth, Newheight, OldWidth, oldheight); }
if (mviewflags & visibility_mask) = = VISIBLE | | mghostview = NULL) { If We are visible, the drawn bit This invalidate would go through (at least to our parent). This was because someone may has invalidated this view Before this call to Setframe came in, thereby clearing The drawn bit. Mprivateflags |= Pflag_drawn; invalidate (sizeChanged); //any child Invalidateparentcaches (); Mprivateflags |= drawn; //android accessibility notice Notifysubtreeaccessibilitystatechangedifneeded (); /span> |
Framelayout#onlayout
If it is a view, after executing the layout method, then he is finished, but if it is viewgroup, then it needs to handle its child view. The main function of OnLayout is to call Layoutchildren, and to lay out a pair of view, so here are layoutchildren.
protected void OnLayout (Boolean changed, int left, int top, int. right, int bottom) { Layoutchildren (left, top, right, bottom, false/* No Force Left gravity */); }
void Layoutchildren (int left, int top, int. right, int bottom, Boolean forceleftgravity) { Final int count = Getchildcount ();
Calculates the upper and lower sides of the parent Final int parentleft = Getpaddingleftwithforeground (); Final int parentright = Right-left-getpaddingrightwithforeground ();
Final int parenttop = Getpaddingtopwithforeground (); Final int parentbottom = Bottom-top-getpaddingbottomwithforeground ();
for (int i = 0; i < count; i++) { Final View child = Getchildat (i); if (child.getvisibility ()! = GONE) { Final Layoutparams LP = (layoutparams) child.getlayoutparams ();
Final int width = child.getmeasuredwidth (); Final int height = child.getmeasuredheight ();
int childleft; int childtop;
int gravity = lp.gravity; if (Gravity = =-1) { Gravity = default_child_gravity; }
Gets the layout default orientation, usually from left to right, in some specific languages, right-to-left Final int layoutdirection = Getlayoutdirection (); The absolute transverse position property is calculated by the direction value just above Final int absolutegravity = gravity.getabsolutegravity (Gravity, layoutdirection); To calculate vertical position properties Final int verticalgravity = gravity & gravity.vertical_gravity_mask;
Calculates the left and right of a child view by using the Position property Switch (absolutegravity & gravity.horizontal_gravity_mask) { Case Gravity.center_horizontal: Childleft = Parentleft + (parentright-parentleft-width)/2 + Lp.leftmargin-lp.rightmargin; Break Case Gravity.right: if (!forceleftgravity) { Childleft = Parentright-width-lp.rightmargin; Break } Case Gravity.left: Default Childleft = Parentleft + lp.leftmargin; }
Calculates the top and bottom of a child view with positional properties Switch (verticalgravity) { Childtop = Parenttop + lp.topmargin; Childtop = Parenttop + (Parentbottom- Parenttop-height)/2 + Lp.topmargin-lp.bottommargin; Childtop = Parentbottom-height-lp.bottommargin; Child.layout (Childleft, childtop, Childleft + width, childtop + height); /span> |
Timing Diagram
Diagram of view layout sequence diagram
Summary
The layout method of view drawing is introduced here. It's a lot easier than measure,layout. But here also reserved some pits, did not explain clearly, such as invalidate, there are rendernode hardware acceleration, and later will write some notes specifically for these knowledge points to do comb.
Series Articles
Android View and view drawing analysis notes Setcontentview
Onmeasure of view Drawing analysis notes
OnLayout of view Drawing analysis notes
OnDraw of view Drawing analysis notes
The onlayout of 3.View drawing analysis notes