This article through 13 ask 13 to learn the Android view drawing for your reference, the specific contents are as follows
1.View drawing process In a few steps, where to start? Which process can see the view after the end?
A: Starting with the performtraversals of Viewroot, after measure,layout,draw three processes. After the draw process is over, you can see the view on the screen.
is there any difference between the measuring width of 2.view and the actual width?
A: Basically 99 of the case can be considered no difference. There are two kinds of situations, there are differences. The first is that sometimes the view will be measured many times for some reason, and that the width of the first measurement is not necessarily equal to the height of the last actual width, but in this case
The last measurement is uniform in width and height. In addition, the actual width of the high is determined in the layout process, we can in the layout process to write the actual width of the death written in hard code, so the measurement of the width and the actual width of the job is certainly different, although this does not mean and not good.
who decides the measurespec of 3.view? What's the top view?
A: By the view of their own layoutparams and the parent container together to determine their own measurespec. Once you have identified the Spec,onmeasure, you can determine the height of the view.
Top view is a little bit special, for decorview measurement in the Viewrootimpl source.
The 2 parameters of desire represent the width and height of the screen, Childwidthmeasurespec = Getrootmeasurespec (Desiredwindowwidth, lp.width);
Childheightmeasurespec = Getrootmeasurespec (Desiredwindowheight, lp.height);
Performmeasure (Childwidthmeasurespec, Childheightmeasurespec); Decorview's Measurespec is here to determine, in fact, than the ordinary view of the measurespec to simple more//code does not analyze a glance at the things 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 is 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;
}
4. For ordinary view, does his measure process relate to the parent view? If so, what role does this parent view, the ViewGroup, play?
Answer: Look Source:
For the measure of ordinary view, it is triggered by the view's parent view, which is viewgroup. Which is the following Measurechildwithmargins method protected void Measurechildwithmargins (View child, int parentwidthmeasurespec, int widthused, int parentheightmeasurespec, int heightused) {//The first step is to obtain the Layoutparams parameter value of the child view final Marginlayoutpar
AMS LP = (Marginlayoutparams) child.getlayoutparams (); Then start to compute the value of the spec for the child view, and notice that the calculation is seen in addition to the Layoutparams parameter of the child View//And the value of the parent view, which is the ViewGroup own spec, final int Childwidthme
Asurespec = Getchildmeasurespec (parentwidthmeasurespec, mpaddingleft + mpaddingright + lp.leftMargin + lp.rightMargin
+ widthused, lp.width); Final int childheightmeasurespec = Getchildmeasurespec (parentheightmeasurespec, mpaddingtop + mPaddingBottom + Lp.topM
Argin + Lp.bottommargin + heightused, lp.height);
Child.measure (Childwidthmeasurespec, Childheightmeasurespec);
}//The view of the spec method looks a lot but really logic is very simple is based on the Father ViewGroup//Meaurespec also have a view of their own params to determine the view of their own measurespec. Note the parameters hereis padding, the meaning of the value is the size of the control that the parent container has occupied so the value of the view specsize//You can see that you want to subtract the value of this padding. Total size-already used = available.
Very well understood. Then the following switch logic needs to be sorted out by itself. In fact, is not difficult, mainly the following principles//If the view using fixed width, that is, the number of dead.
Regardless of the father's spec value, the view spec is definitely exactly and the size follows the size set in the layout parameter. If the view of the width is match_parent, it is necessary to see the viewgroup of the spec of the parent container, if the spec of the parent view is exactly mode,//That view is definitely exactly, and the size is the left space for the parent container. If the parent container is At_most mode, the view is also at_most and does not exceed the remaining space size//If the view's width is wrap_content, then regardless of the spec of the parent container, the view spec must be At_most
And does not exceed the size of the remaining space in the parent view. public static int Getchildmeasurespec (int spec, int padding, int childdimension) {int specmode = Measurespec.getmode (sp
EC);
int specsize = measurespec.getsize (spec);
int size = Math.max (0, specsize-padding);
int resultsize = 0;
int resultmode = 0; Switch (Specmode) {//Parent has imposed an exact size to US case MeasureSpec.EXACTLY:if (childdimension >= 0)
{resultsize = childdimension;
Resultmode = measurespec.exactly; else if (childdimension = layoutparams.match_parent) {//ChildWants to is our size.
So is it.
resultsize = size;
Resultmode = measurespec.exactly; else if (childdimension = = layoutparams.wrap_content) {//child wants to determine its own size.
It can ' t be//bigger than us.
resultsize = size;
Resultmode = Measurespec.at_most;
} break; Parent has imposed a maximum size on US case MeasureSpec.AT_MOST:if (childdimension >= 0) {//child wants
A specific size ... so is it resultsize = childdimension;
Resultmode = measurespec.exactly;
else if (childdimension = = layoutparams.match_parent) {//child wants to being our size, but we are not fixed.
Constrain is bigger than us.
resultsize = size;
Resultmode = Measurespec.at_most; else if (childdimension = = layoutparams.wrap_content) {//child wants to determine its own size.
It can ' t be//bigger than us.
resultsize = size;
Resultmode = Measurespec.at_most;
} break; ParentAsked to-to-you-how-we-want-MeasureSpec.UNSPECIFIED:if (childdimension >= 0) {//child wants a s
Pecific size ... let him have it resultsize = childdimension;
Resultmode = measurespec.exactly;
else if (childdimension = = layoutparams.match_parent) {//child wants to is our size ... find out how big it should Be resultsize = View.susezerounspecifiedmeasurespec?
0:size;
Resultmode = measurespec.unspecified;
else if (childdimension = = layoutparams.wrap_content) {//child wants to determine its own size ... Big it should be resultsize = View.susezerounspecifiedmeasurespec?
0:size;
Resultmode = measurespec.unspecified;
} break;
Return Measurespec.makemeasurespec (resultsize, Resultmode);
}
What is the relationship between 5.view Meaure and onmeasure?
Answer: Look Source:
The measure of view is the final method that our subclasses cannot modify.
Public final void measure (int widthmeasurespec, int heightmeasurespec) {Boolean optical = islayoutmodeoptical (this);
if (Optical!= islayoutmodeoptical (mparent)) {Insets Insets = Getopticalinsets ();
int owidth = Insets.left + insets.right;
int oheight = insets.top + insets.bottom;
Widthmeasurespec = Measurespec.adjust (widthmeasurespec, optical-owidth:owidth);
Heightmeasurespec = Measurespec.adjust (heightmeasurespec, optical-oheight:oheight); }//Suppress sign extension for the low bytes long key = (long) Widthmeasurespec << 32 |
(long) Heightmeasurespec & 0xffffffffL;
if (Mmeasurecache = = null) Mmeasurecache = new Longsparselongarray (2);
if ((Mprivateflags & pflag_force_layout) = = Pflag_force_layout | |
Widthmeasurespec!= Moldwidthmeasurespec | | Heightmeasurespec!= Moldheightmeasurespec) {//The clears measured dimension-flag mprivateflags &= ~PFL Ag_measured_dimensiOn_set;
Resolvertlpropertiesifneeded (); int cacheindex = (Mprivateflags & pflag_force_layout) = = Pflag_force_layout?
-1:mmeasurecache.indexofkey (key);
if (CacheIndex < 0 | | signoremeasurecache) {//measure ourselves, this should set the measured dimension flag
Onmeasure (Widthmeasurespec, Heightmeasurespec);
MPRIVATEFLAGS3 &= ~pflag3_measure_needed_before_layout;
else {Long value = Mmeasurecache.valueat (CacheIndex); Casting a long to int drops-bits, no mask needed setmeasureddimensionraw (int) (value >>), (in
t) value);
MPRIVATEFLAGS3 |= pflag3_measure_needed_before_layout; }//Flag not set, Setmeasureddimension () is not invoked, we raise//a exception to warn the developer if ((m Privateflags & Pflag_measured_dimension_set)!= Pflag_measured_dimension_set) {throw new IllegalStateException ("V Iew with id "+ getId () +": "+ getclass (). GetName () +" #onMeasure () didNot set the "+" measured dimension by calling "+ Setmeasureddimension ()");
} mprivateflags |= pflag_layout_required;
} Moldwidthmeasurespec = Widthmeasurespec;
Moldheightmeasurespec = Heightmeasurespec;
Mmeasurecache.put (Key, (long) mmeasuredwidth) << 32 | (long) Mmeasuredheight & 0xffffffffL);
Suppress sign Extension}//However, you can see that the Onmeasure method is invoked in the measure method so that we can know that we must override this method when customizing the view! protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {setmeasureddimension (Getdefaultsize (
Getsuggestedminimumwidth (), Widthmeasurespec), Getdefaultsize (Getsuggestedminimumheight (), heightMeasureSpec));
}
6. A brief analysis of the measure process of view?
A: First of all, review the problem 4,viewgroup the spec of the child view will call the measure method of the child view, and the measure method of the child view we've seen it in question 5. The Onmeasure method that is actually invoked
So all we have to do is analyze the Onmeasure method, and note that the Onmeasure method's parameters are the values of the 2 specs that are calculated by his parent view (the measure method in this view will slightly modify the Specsize value in this spec. Do not do analysis because the measure method modifies the Specsize part is very simple).
You can see that this is the Setmeasureddimension method call this method to see the name is to determine the view of the measurement of wide//So the focus of our analysis is to see how the Getdefaultsize method determines the view of the measurement of the width of the high protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {setmeasureddimension (Getdefaultsize (
Getsuggestedminimumwidth (), Widthmeasurespec), Getdefaultsize (Getsuggestedminimumheight (), heightMeasureSpec)); }//This method is particularly simple and basically can be thought of as approximate return to the specsize in spec, unless your specmode is UNSPECIFIED//unspecified This is usually used in system internal measurement to, this time return size
That is, the return value of getsuggestedminimumwidth public static int getdefaultsize (int size, int measurespec) {int = size;
int specmode = Measurespec.getmode (Measurespec);
int specsize = measurespec.getsize (Measurespec);
Switch (specmode) {case MeasureSpec.UNSPECIFIED:result = size;
Break
Case MeasureSpec.AT_MOST:case MeasureSpec.EXACTLY:result = specsize;
Break
return result; ///view background not much to do analysis of the protected int getsuggestedminimumwidth () {return (Mbackground = = null)? Mminwidth:max (MMINW Idth, Mbackground. Getminimumwidth ());
}
7. Custom View what happens if the Onmeasure method does not handle wrap_content? Why? How to solve?
A: If you do not deal with wrap_content, even if you set it to Wrap_content in XML. The effect is the same as match_parent. Look at the analysis of question 4. We can know that the view of their own layout as wrap, that mode is at_most (regardless of Father View is what Specmode).
The width of this pattern is equal to Specsize (getdefaultsize function Analysis), and the specsize here is obviously the size of parentsize. That is, the remaining size of the parent container. Isn't that the same effect that we set up directly as Match_parent?
The solution is to do special processing for wrap in onmeasure such as specifying a default width-height, when found to be wrap_content set this default width.
is there a onmeasure method for 8.ViewGroup? Why not?
A: No, this method is to be implemented by the subclass itself. Different ViewGroup the layout is certainly not the same, that Onmeasure simply give them all to achieve good.
9. Why is it impossible to measure the height of the activity during the life cycle? Is there any way to solve this problem?
A: Because the measure process has nothing to do with the life cycle of the activity. You cannot be sure which life cycle will be completed after the measure process of the view. You can try the following methods to get the measurement width of the view.
This method of overriding the activity is public
void Onwindowfocuschanged (Boolean hasfocus) {
super.onwindowfocuschanged (hasfocus );
if (hasfocus) {
int width = tv.getmeasuredwidth ();
int height = tv.getmeasuredheight ();
LOG.V ("Burning", "width==" + width);
LOG.V ("Burning", "height==" + height);
}
or rewrite the method.
@Override
protected void OnStart () {
super.onstart ();
Tv.post (New Runnable () {
@Override public
void Run () {
int width = tv.getmeasuredwidth ();
int height = tv.getmeasuredheight ();}}
);
Again or:
@Override
protected void OnStart () {
super.onstart ();
Viewtreeobserver observer = Tv.getviewtreeobserver ();
Observer.addongloballayoutlistener (New Viewtreeobserver.ongloballayoutlistener () {
@Override public
Void Ongloballayout () {
int width = tv.getmeasuredwidth ();
int height = tv.getmeasuredheight ();
Tv.getviewtreeobserver (). Removeongloballayoutlistener (this);
}
);
What is the difference between 10.layout and OnLayout methods?
A: Layout is to determine the location of the view itself and onlayout is to determine the location of all child elements. Layout inside is to set the position of the four vertices of the view by the Serframe method. These 4 positions to determine the location of your view is fixed
The onlayout is then invoked to determine the position of the child element. Neither the view nor the ViewGroup OnLayout method is written. and leave it all to ourselves. Child element Layout
How many steps does the 11.draw method have?
A: There are 4 steps to draw the background---------draw your own--------draw Chrildren----Draw the decorations.
What's the use of the 12.setWillNotDraw method?
A: This method is in view.
/**
* If This view doesn ' t does any drawing in its own, the set this flag to * allow further
. By default, this flag isn't set
on * view, but could to set on some view subclasses such as ViewGroup.
*
* Typically, if you override {@link #onDraw (Android.graphics.Canvas)}
* Your should clear this flag.
*
* @param willnotdraw whether or not-View draw on its own
/public void Setwillnotdraw (Boolean willnot Draw) {
setflags (Willnotdraw?) will_not_draw:0, draw_mask);
Used to set the flag bit, which means that if your custom view doesn't need to be draw, you can set this method to true. So the system knows that your view does not need draw to optimize execution speed. ViewGroup generally set this to true by default, since ViewGroup are mostly responsible for layout only
Not responsible for the draw. and view this sign is generally closed by default.
13. What are some points to be aware of in customizing view?
Answer: The main is to deal with wrap_content and padding. Otherwise, setting these 2 properties over the XML is no use at all. And do not use handler in view because someone else has provided a post method. If it is inherited from ViewGroup, it should also be considered in Onmeasure and onlayout.
The effects of padding and layout. That means specsize to count. Finally, if the view animation or thread needs to be stopped, consider doing it in the Ondetachedfromwindow.
For the above points, give a few simple custom view for everyone to understand.
Give a rounded view example:
Package com.example.administrator.motioneventtest;
Import Android.content.Context;
Import Android.graphics.Canvas;
Import Android.graphics.Color;
Import Android.graphics.Paint;
Import Android.util.AttributeSet;
Import Android.view.View;
/** * Created by the Administrator on 2016/2/4.
* * public class Circleview extends View {private int mcolor = color.red;
Private Paint Mpaint = new Paint (Paint.anti_alias_flag);
private void Init () {mpaint.setcolor (mcolor); @Override 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); Case when processing as wrap_content if (Widthspecmode = = Measurespec.at_most && Heightspecmode = = measurespec.at_most) {SE TmeasureddimEnsion (200, 200);
else if (Widthspecmode = = measurespec.at_most) {setmeasureddimension (heightspecsize);
else if (Heightspecmode = = measurespec.at_most) {setmeasureddimension (widthspecsize, 200);
} @Override protected void OnDraw (Canvas Canvas) {Super.ondraw (Canvas);
The situation of processing padding final int paddingleft = Getpaddingleft ();
Final int paddingright = Getpaddingright ();
Final int paddingtop = Getpaddingtop ();
Final int paddingbottom = Getpaddingbottom ();
int width = getwidth ()-paddingleft-paddingright;
int height = getheight ()-paddingtop-paddingbottom;
int radius = math.min (width, height)/2;
Canvas.drawcircle (paddingleft + WIDTH/2, paddingtop + height/2, radius, mpaint);
Public Circleview (context, AttributeSet attrs, int defstyleattr) {Super (context, attrs, defstyleattr);
Init ();
Public Circleview {Super (context);
Init (); Public Circleview, AttributeSet attrs) {Super (context, attrs);
Init ();
}
}
And then give an example, a little more complex is a custom viewgroup (mainly to enhance the understanding of onmeasure and OnLayout), the requirements are as follows:
A horizontal viewgroup, the inner child element for simplicity we assume that their width is the same. To write a simple viewgroup such as this.
Package com.example.administrator.motioneventtest;
Import Android.content.Context;
Import Android.util.AttributeSet;
Import Android.util.Log;
Import Android.view.View;
Import Android.view.ViewGroup;
/** * Created by the Administrator on 2016/2/4. *////Here we only deal with the state of the padding margin, the margin of the child view on measure and layout, and leave it to the reader to complete the public class
Customhorizontallayout extends ViewGroup {//Set default control minimum is no custom attribute is provided here. You can expand the final int minheight = 0 by yourself in the code.
Final int minwidth = 0;
Public Customhorizontallayout {Super (context);
Public Customhorizontallayout (context, AttributeSet attrs) {Super (context, attrs); Customhorizontallayout (context, AttributeSet attrs, int defstyleattr) {Super (context, Attrs, defstyl
EATTR); @Override protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {super.onmeasure (Widthmeasurespec,
HEIGHTMEASURESPEC);
int measurewidth = 0;
int measureheight = 0; Final int childcount = Getchildcount ();
Measurechildren (Widthmeasurespec, Heightmeasurespec);
int widthspecmode = Measurespec.getmode (Widthmeasurespec);
int widthspecsize = measurespec.getsize (Widthmeasurespec);
int heightspecmode = Measurespec.getmode (Heightmeasurespec);
int heightspecsize = measurespec.getsize (Heightmeasurespec);
Final View Childview = getchildat (0);
Final int paddingleft = Getpaddingleft ();
Final int paddingright = Getpaddingright ();
Final int paddingtop = Getpaddingtop ();
Final int paddingbottom = Getpaddingbottom (); Our wide Gaoyao for special handling when there are no child controls if (ChildCount = = 0) {//when there is no child control, if the width has one for wrap then let the control show in the smallest form//Here we have the minimum set to 0 if (widthspec Mode = = Measurespec.at_most | |
Heightspecmode = = measurespec.at_most) {setmeasureddimension (minwidth, minheight);
else {//otherwise, according to our layout property setmeasureddimension (Getlayoutparams (). Width, getlayoutparams (). height); } else if (Widthspecmode = measurespec.at_most && Heightspecmode = = Measurespec.at_mosT) {measurewidth = Childview.getmeasuredwidth () * CHILDCOUNT;
Measureheight = Childview.getmeasuredheight ();
Setmeasureddimension (paddingleft + measurewidth + paddingright, paddingtop + measureheight + paddingBottom);
else if (Heightspecmode = = measurespec.at_most) {measureheight = Childview.getmeasuredheight ();
Setmeasureddimension (paddingleft + paddingright + widthspecsize, paddingtop + paddingbottom + measureHeight);
else if (Widthspecmode = = measurespec.at_most) {measurewidth = Childview.getmeasuredwidth () * CHILDCOUNT;
Setmeasureddimension (paddingleft + paddingright + measurewidth, paddingtop + paddingbottom + heightSpecSize); } @Override protected void OnLayout (Boolean changed, int l, int t, int r, int b) {final int paddingleft = Getpadd
Ingleft ();
Final int paddingright = Getpaddingright ();
Final int paddingtop = Getpaddingtop ();
Final int paddingbottom = Getpaddingbottom ();
The left initial position is 0 int childleft = 0 + paddingleft; Final INT ChildCount = Getchildcount ();
for (int i = 0; i < ChildCount i++) {final View Childview = Getchildat (i);
if (childview.getvisibility ()!= view.gone) {final int childwidth = Childview.getmeasuredwidth ();
Childview.layout (childleft, 0 + paddingtop, Childleft + childwidth, Paddingtop + childview.getmeasuredheight ());
Childleft + = Childwidth;
}
}
}
}
The above is the entire content of this article, I hope to help you learn.