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 the source code
Android View System (vii) The measure process for interpreting view from source code
Preface
In the previous article we talked about the measure process of view, and then we'll talk about the layout and draw process of view, and if you understand the measure process of view, this article will be a cinch.
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 are the coordinates of the four points of the view, the coordinates of which are not relative to the origin of the screen, and relative to its parent layout. L and T are the distance between the left and top edges of the child controls relative to the left and top edges of the parent 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 location is determined differently 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 simple, 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); } }
Note from the source code we see the draw process has six steps:
- If background is set, the background is drawn
- Save Canvas Layer
- Draw your own content
- Draw child elements
- Drawing effect
- Painting Decorations (scrollbars)
Well, here's the workflow for view, and then we'll talk about custom view.
Android View System (eight) analyze the layout and draw process of view from source code