Related articles
Android View System (i) Views coordinate system
Android View System (ii) six ways to implement view swipe
Android View System (iii) property animation
Android View System (iv) parsing from source code scroller
Android View System (v) the event distribution mechanism for resolving view from source code
Android View System (vi) parsing the composition of activity from source code
Android View System (vii) measure process for resolving view from source code
Preface
In the previous article we talked about the measure process of view. Next we'll talk about the layout and draw flow of the view, assuming you understand the measure process of the view. Then this article is a natural one.
layout process for 1.View
First look at the layout () method of view:
Public void Layout(intLintTintRintb) {if((MPRIVATEFLAGS3 & pflag3_measure_needed_before_layout)! =0) {onmeasure (Moldwidthmeasurespec, Moldheightmeasurespec); MPRIVATEFLAGS3 &= ~pflag3_measure_needed_before_layout; }intOLDL = Mleft;intOldt = Mtop;intOldb = Mbottom;intOldr = Mright; Boolean changed = Islayoutmodeoptical (mparent)? Setopticalframe (L, T, R, B): Setframe (L, T, R, b);if(Changed | | (Mprivateflags & pflag_layout_required) = = pflag_layout_required) {onlayout (changed, L, T, R, b); Mprivateflags &= ~pflag_layout_required; Listenerinfo li = mlistenerinfo;if(Li! =NULL&& Li.monlayoutchangelisteners! =NULL) {arraylist<onlayoutchangelistener> listenerscopy = (arraylist<onlayoutch angelistener>) Li.mOnLayoutChangeListeners.clone ();intNumlisteners = Listenerscopy.size (); for(inti =0; i < numlisteners; ++i) {listenerscopy.Get(i). Onlayoutchange ( This, L, T, R, B, Oldl, Oldt, Oldr, OLDB); }}} mprivateflags &= ~pflag_force_layout; MPRIVATEFLAGS3 |= pflag3_is_laid_out; }
The four parameters that are passed in are the coordinates of the four points of the view. Its coordinates are not relative to the original point of the screen, and are relative to its parent layout.
L and T are the distance between the left and top edges of the child control relative to the left and top edges of the parent class control.
R and B are the distance between the right and bottom edges of the child controls relative to the left and top edges of the parent class control. Take a look at what the Setframe () method says:
protected Boolean Setframe(intLeftintTopintRightintBottom) {BooleanChanged =false;if(DBG) {LOG.D ("View", This+"View.setframe ("+ Left +","+ Top +","+ Right +","+ Bottom +")"); }if(Mleft! = left | | Mright! = RIGHT | | Mtop! = TOP | | Mbottom! = bottom) {changed =true;//Remember our drawn bit intDrawn = Mprivateflags & pflag_drawn;intOldWidth = Mright-mleft;intOldHeight = Mbottom-mtop;intNewwidth = Right-left;intNewheight = Bottom-top;BooleansizeChanged = (newwidth! = oldwidth) | | (Newheight! = oldheight);//Invalidate our old positionInvalidate (sizeChanged); Mleft = left; Mtop = top; Mright = right; Mbottom = bottom; Mrendernode.setlefttoprightbottom (Mleft, Mtop, Mright, Mbottom); ... OmittedreturnChanged }
The Setframe () method is used primarily to set the values of the four vertices of the view, that is, the values of Mleft, Mtop, Mright, and Mbottom. After calling the Setframe () method, call the OnLayout () method:
protectedvoidonLayout(booleanintintintint bottom) { }
The OnLayout () method does not do anything, this is similar to the Onmeasure () method, where the position is determined by different implementations depending on the control, so the OnLayout () method is not implemented in both view and ViewGroup.
In that case, let's take a look at LinearLayout's OnLayout () method:
@Override protectedvoidonLayout(booleanintintintint b) { if (mOrientation == VERTICAL) { layoutVertical(l, t, r, b); else { layoutHorizontal(l, t, r, b); } }
What did layoutvertical do?
voidLayoutvertical (intLeftintTopintRightintBottom) {Final intPaddingleft = Mpaddingleft;intChildtop;intChildleft;//Where right end of the child should go Final intwidth = right-left;intChildright = Width-mpaddingright;//Space available for child intChildspace = Width-paddingleft-mpaddingright;Final int Count= Getvirtualchildcount ();Final intmajorgravity = mgravity & gravity.vertical_gravity_mask;Final intminorgravity = mgravity & gravity.relative_horizontal_gravity_mask;Switch(majorgravity) { CaseGravity.bottom://Mtotallength contains the padding alreadyChildtop = Mpaddingtop + bottom-top-mtotallength; Break;//Mtotallength contains the padding already CaseGravity.CENTER_VERTICAL:childTop = Mpaddingtop + (bottom-top-mtotallength)/2; Break; CaseGravity.top:default: Childtop = mpaddingtop; Break; } for(inti =0; I <Count; i++) {FinalView child = Getvirtualchildat (i);if(Child = =NULL) {Childtop + = Measurenullchild (i); }Else if(Child.getvisibility ()! = GONE) {Final intChildwidth = Child.getmeasuredwidth ();Final intChildheight = Child.getmeasuredheight ();FinalLinearlayout.layoutparams LP = (linearlayout.layoutparams) child.getlayoutparams ();intGravity = lp.gravity;if(Gravity <0) {gravity = minorgravity; }Final intLayoutDirection = Getlayoutdirection ();Final intabsolutegravity = Gravity.getabsolutegravity (Gravity, layoutdirection);Switch(Absolutegravity & Gravity.horizontal_gravity_mask) { CaseGravity.CENTER_HORIZONTAL:childLeft = Paddingleft + ((childspace-childwidth)/2) + Lp.leftmargin-lp.rightmargin; Break; CaseGravity.RIGHT:childLeft = Childright-childwidth-lp.rightmargin; Break; CaseGravity.left:default: Childleft = paddingleft + lp.leftmargin; Break; }if(Hasdividerbeforechildat (i)) {childtop + = Mdividerheight; } childtop + = Lp.topmargin; Setchildframe (Child, Childleft, Childtop + getlocationoffset (child), Childwidth, childheight); Childtop + = childheight + Lp.bottommargin + getnextlocationoffset (child); i + = Getchildrenskipcount (child, I); } } }
This method iterates through the child elements and calls the Setchildframe () method:
privatevoidsetChildFrameintintintint height) { child.layout(left, top, left + width, top + height); }
Call the layout () method of the child element in the Setchildframe () method to determine its position. We see childtop this value is gradually increasing, this is to in the vertical direction, the child elements are arranged one by one instead of overlapping.
draw process for 2.View
The draw process for view is very easy. First look at the draw () method of view:
Public void Draw(Canvas canvas) {Final intPrivateflags = Mprivateflags;Final BooleanDirtyopaque = (Privateflags & pflag_dirty_mask) = = Pflag_dirty_opaque && (Mattachinfo = =NULL|| !mattachinfo.mignoredirtystate); Mprivateflags = (privateflags & ~pflag_dirty_mask) | Pflag_drawn;//Step 1, draw the background, if needed intSavecount;if(!dirtyopaque) {drawbackground (canvas); }... Omitted//Step 2, Save the canvas ' layers intPaddingleft = Mpaddingleft;Final Booleanoffsetrequired = ispaddingoffsetrequired ();if(offsetrequired) {paddingleft + = Getleftpaddingoffset (); }... Omitted//Step 3, draw the content if(!dirtyopaque) OnDraw (canvas);//Step 4, Draw the childrenDispatchdraw (canvas); Omitted//Step 5, draw the fade effect and restore layers FinalPaint p = scrollabilitycache.paint;FinalMatrix matrix = Scrollabilitycache.matrix;FinalShader fade = Scrollabilitycache.shader; Omitted//Step 6, Draw decorations (scrollbars)Ondrawscrollbars (canvas);if(Moverlay! =NULL&&!moverlay.isempty ()) {Moverlay.getoverlayview (). Dispatchdraw (canvas); } }
From the gaze of the source code we see a draw process with six steps. The steps 2nd and 5th can be skipped:
- Suppose there is a setting background. Then draw the background
- Save Canvas Layer
- Draw your own content
- If you have child elements, draw child elements
- Drawing effect
- Painting Decorations (scrollbars)
Well, the workflow for view is here, and then we'll talk about defining view.
Android View System (eight) parsing view's layout and draw process from source code