[Android] Custom ViewGroup best practices for getting Started

Source: Internet
Author: User

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

    • Measure () and onmeasure ()

      In the View.java source code:
        

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.

    • Measure

      Traversal from top to bottom, based on the parent view of the measurespec of the child view and the parameters of the Childview itself, by
        

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)
  

    • Measurespecs

      Measurement specifications, including information on measurement requirements and dimensions, are available in three modes:

①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

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.