The custom view is not very familiar with the code friends can first look at the custom view to get started this article, this article mainly on the custom viewgroup process of carding, nonsense not much to say.
1.View Drawing Process
ViewGroup is also inherited from view, below to see which functions are called in turn during the drawing process.
Description
public final void measure(int widthMeasureSpec,int heightMeasureSpec){... onMeasure...}protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec) { setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));}
It can be seen that measure () is final modified and cannot be rewritten. Onmeasure is called in the measure method, and when we inherit the view, we measure the size of the control by overriding the Onmeasure method.
Layout () and onlayout (), Draw () and OnDraw () are similar.
Dispatchdraw ()
This function in View is an empty function, ViewGroup dispatchdraw () to draw on its child view. Custom ViewGroup generally do not replicate Dispatchdraw ().
Requestlayout ()
When the layout changes, such as the direction change, the size change, will call the method, in the custom view, if you want to re-measure the size in some cases, you should manually call the method, it will trigger the measure () and layout () process, but will not draw.
General replication when customizing the ViewGroup
Onmeasure () Method:
Calculate the measured values and patterns of the Childview, and set their own width and height
OnLayout () method,
Position all of its childview
View Tree:
The traversal of the tree is orderly, from the parent view to the child view, and each viewgroup is responsible for mapping all its sub-views, while the bottom view is responsible for mapping itself.
getChildMeasureSpec(parentHeightMeasure,mPaddingTop+mPaddingBottom,lp.height)
Get Childview Measurespec, callback childview.measure final call setmeasureddimension get Childview size:
mMeasuredWidth 和 mMeasuredHeight
Layout:
It is also a top-down traversal, which calculates the childleft,childtop of each childview, and Mmeasuredwidth and mmeasuredheight of each childview obtained with measure, To lay out the Childview.
child.layout(left,top,left+width,top+height)
2.onMeasure process
The measure process will be the mmeasuredwidth of a view and all child nodes
and the Mmeasuredheight variable assignment, which can be obtained through the getmeasuredwidth () and Getmeasuredheight () methods.
The onmeasure process passes a size of two classes:
viewgroup.layoutparams (viewgroup own layout parameters)
To specify parameters such as the height and width of the view, use the View.getlayoutparams () method to get a view layoutparams, which gets the layoutparams of its parent view type. For example, if the view's parent control is relativelayout, then the resulting layoutparams type is relativelayoutparams.
① Specific values
②match_parent indicates that the child view wants to be as large as the parent view (does not contain padding values)
③wrap_content indicates that the view is capable of wrapping its content size (including padding values)
①unspecified
The parent view does not have any constraints on the child view, it can reach any desired size. such as ListView, ScrollView, General custom View in the use of less than
②exactly
The parent view specifies an exact size for the child view, and regardless of how large the child view is expected, it must be within the bounds of the specified size, the corresponding property is Match_parent or a specific value, such as 100DP, the parent control can be measurespec.getsize ( MEASURESPEC) to get the dimensions of the child controls directly.
③at_most
The parent view specifies a maximum size for the child view. The child view must ensure that all its child views can be adapted to that dimension, and that the corresponding property is Wrap_content, in which case the parent control cannot determine the size of the child view, and only the sub-control can calculate its own size on demand. This pattern is what we need to implement the measurement logic for our custom view.
3.onLayout process
The specific location of the child view is relative to the parent view. The OnLayout method for View is an empty implementation, and the ViewGroup onlayout is abstract, so onlayout functions must be implemented if custom viewgroup are customized.
In the layout process, the child view calls the Getmeasuredwidth () and Getmeasuredheight () methods to get mmeasuredwidth and mmeasuredheight to the measure process, as their own Width and height. The layout (l, T, R, b) function of each sub-view is then called to determine the position of each child view in the parent view.
4. Sample Programs
First on:
There are detailed comments in the code, which, in conjunction with the instructions above, should not be a problem. The core code is mainly posted here.
Flowlayout.java (refer to male deity's course)
Onmeasure method
@Override protected void onmeasure(intWidthmeasurespec,intHEIGHTMEASURESPEC) {//Get its parent container to set the measurement mode and size for it intSizewidth = Measurespec.getsize (Widthmeasurespec);intModewidth = Measurespec.getmode (Widthmeasurespec);intSizeheight = Measurespec.getsize (Heightmeasurespec);intModeheight = Measurespec.getmode (Heightmeasurespec);//For warp_content cases, to record the parent view width and height intwidth =0;intHeight =0;//Take the maximum width of each line intLineWidth =0;//height accumulation for each row intLineheight =0;//Get the number of child view intCcount = Getchildcount (); for(inti =0; i < ccount; i++) {View child = Getchildat (i);//Measure sub-view width and height (sub view in Layout file is Wrap_content)Measurechild (Child, Widthmeasurespec, Heightmeasurespec);//Get LayoutparamsMarginlayoutparams LP = (marginlayoutparams) child.getlayoutparams ();the actual width of the child view is calculated based on the measured width plus the margin value (described above) intChildwidth = child.getmeasuredwidth () + Lp.leftmargin + lp.rightmargin;//calculates the actual height of the sub-view according to the measurement height plus the margin value intChildheight = child.getmeasuredheight () + lp.topmargin+ lp.bottommargin;//The parent view here has a padding value, and if you add an element more than the maximum width, wrap the line if(LineWidth + childwidth > Sizewidth-getpaddingleft ()-getpaddingright ()) {//Parent View width = Previous parent view width, maximum value of current line widthwidth = Math.max (width, linewidth);//newline, current line width = width of first viewLineWidth = Childwidth;//The height of the parent view = The sum of the height of each rowHeight + = lineheight;//Line up, current row height = height of First viewLineheight = Childheight; }Else{//Overlay row widthLineWidth + = Childwidth;//Get the maximum height of the current rowLineheight = Math.max (lineheight, childheight); }//Last control if(i = = Ccount-1) {width = Math.max (linewidth, width); Height + = lineheight; } }/** * Exactly corresponds to match_parent or specific value * at_most corresponds to Wrap_content * in FlowLayout layout file * Android: Layout_width= "fill_parent" * android:layout_height= "wrap_content" * * if it is measurespec.exactly use the parent directly ViewGroup incoming width and height, otherwise set to calculate the width and height. */Setmeasureddimension (Modewidth = = measurespec.exactly? Sizewidth:width + getpaddingleft () + GetPaddingR Ight (), modeheight = = measurespec.exactly? Sizeheight:height + getpaddingtop () + getpaddingbottom ()); }
OnLayout method
//Storage of all view PrivateList<list<view>> mallviews =NewArraylist<list<view>> ();//Store the height of each row PrivateList<integer> mlineheight =NewArraylist<integer> ();@Override protected void OnLayout(BooleanChangedintLintTintRintb) {mallviews.clear (); Mlineheight.clear ();//width of current ViewGroup intwidth = getwidth ();intLineWidth =0;intLineheight =0;//Store all Childview on each lineList<view> lineviews =NewArraylist<view> ();intCcount = Getchildcount (); for(inti =0; i < ccount; i++) {View child = Getchildat (i); Marginlayoutparams LP = (marginlayoutparams) child.getlayoutparams ();intChildwidth = Child.getmeasuredwidth ();intChildheight = Child.getmeasuredheight (); LineWidth + = childwidth + Lp.leftmargin + lp.rightmargin; Lineheight = Math.max (lineheight, childheight + lp.topmargin+ lp.bottommargin); Lineviews.add (child);//newline, Childwidth is added margin value in Onmeasure if(childwidth + linewidth + lp.leftmargin + lp.rightmargin > Width-getpaddingleft ()-getpaddingright ()) {//Record row heightMlineheight.add (lineheight);//record views of the current lineMallviews.add (lineviews);//Line width and row heights for new rowsLineWidth =0; Lineheight = childheight + Lp.topmargin + lp.bottommargin;//New Line View collectionLineviews =NewArraylist<view> (); } }//Processing last lineMlineheight.add (lineheight); Mallviews.add (lineviews);//Set the location of the child view intleft = Getpaddingleft ();inttop = Getpaddingtop ();//number of rows intLineNum = Mallviews.size (); for(inti =0; i < linenum; i++) {//When all the view of the forwardLineviews = Mallviews.get (i); Lineheight = Mlineheight.get (i); for(intj =0; J < Lineviews.size (); J + +) {View child = Lineviews.get (j);//Determine the status of child if(child.getvisibility () = = View.gone) {Continue; } marginlayoutparams LP = (marginlayoutparams) child.getlayoutparams ();intLC = left + Lp.leftmargin;intTC = top + lp.topmargin;intRC = LC + Child.getmeasuredwidth ();intBC = TC + child.getmeasuredheight ();//Layout for child viewChild.layout (LC, TC, RC, BC); Left + = Child.getmeasuredwidth () + lp.leftmargin+ lp.rightmargin; } left = Getpaddingleft (); Top + = Lineheight; } }/** * Because we only need to support margin, so use the system directly Marginlayoutparams * / @Override PublicLayoutparamsGeneratelayoutparams(AttributeSet attrs) {return NewMarginlayoutparams (GetContext (), attrs); }
and Mainactivity.java
Public class mainactivity extends Activity {Layoutinflater Minflater;@InjectView(R.ID.ID_FLOWLAYOUT1) FlowLayout idFlowlayout1;@InjectView(R.ID.ID_FLOWLAYOUT2) FlowLayout IdFlowlayout2;Privatestring[] Mvals =NewString[] {"Do","One thing","At a Time","And do well .","Never","Forget","to say","Thanks.","Keep on","Going","Never give up."};@Override protected void onCreate(Bundle savedinstancestate) {Super. OnCreate (Savedinstancestate); Setcontentview (R.layout.activity_main); Butterknife.inject ( This); Minflater = Layoutinflater.from ( This); InitFlowlayout2 (); } Public void InitFlowlayout2() { for(inti =0; i < mvals.length; i++) {FinalRelativelayout rl2 = (relativelayout) minflater.inflate (R.layout.flow_layout, IdFlowlayout2,false); TextView TV2 = (TextView) Rl2.findviewbyid (r.id.tv); Tv2.settext (Mvals[i]); Rl2.settag (i); Idflowlayout2.addview (RL2); Rl2.setonclicklistener (NewView.onclicklistener () {@Override Public void OnClick(View v) {inti = (int) V.gettag (); ADDVIEWTOFLOWLAYOUT1 (i); Rl2.setbackgroundresource (R.DRAWABLE.FLOW_LAYOUT_DISABLE_BG); } }); } } Public void ADDVIEWTOFLOWLAYOUT1(inti) {relativelayout rl1 = (relativelayout) minflater.inflate (R.layout.flow_layout, IDFLOWLAYOUT1,false); ImageView IV = (ImageView) Rl1.findviewbyid (R.ID.IV); Iv.setvisibility (view.visible); TextView TV1 = (TextView) Rl1.findviewbyid (r.id.tv); Tv1.settext (Mvals[i]); Rl1.settag (i); Idflowlayout1.addview (RL1); Rl1.setonclicklistener (NewView.onclicklistener () {@Override Public void OnClick(View v) {inti = (int) V.gettag (); Idflowlayout1.removeview (v); View view = Idflowlayout2.getchildat (i); View.setbackgroundresource (R.DRAWABLE.FLOW_LAYOUT_BG); } }); }
This project source code has been nearly uploaded, want to see the source of friends can
Click FlowLayout
If there is any doubt can give me a message, the lack of welcome on GitHub Point, thank you!
[Android] Custom ViewGroup best practices for getting Started