Android in layman's custom control (ii)

Source: Internet
Author: User

In my last Post, Android Deep move out of the definition control (i) describes how to customize the View control, this post mainly describes how to customize the ViewGroup


What is ViewGroup?in the tree Chart of Android, the ViewGroup class derives from the familiar layout of LinearLayout, Relativelayout , and so on:


Simply put, ViewGroup is actually the equivalent of all the layouts of the father, so we can implement the ever-changing layout by customizing the ViewGroup class.



Custom ViewGroup is mainly divided into the following steps:1. Create a custom ViewGroup class that inherits from the ViewGroup class, overriding the three constructor methods of ViewGroup
2. Override the Onmeasure method to set the size of the viewgroup and its child view displayed on the interface
3. Adding parameters
4. Rewrite the OnLayout method, set the layout of the child view, this method is also the most critical, it determines the characteristics of your custom layout



1. Create a custom ViewGroup class that inherits from the ViewGroup class, overriding the three constructor methods of ViewGroup

public class Flowlayoutextends Viewgroup{public FlowLayout (Context context) {//TODO auto-generated constructor Stubthis (Context,null);} Public FlowLayout (context context, AttributeSet attrs) {//TODO auto-generated constructor Stubthis (context,attrs,0);} Public FlowLayout (context context, AttributeSet attrs, int defstyleattr) {Super (context, attrs, defstyleattr);//TODO Aut o-generated constructor stub}}



2. Override the Onmeasure method to set the size of the viewgroup and its child view displayed on the interface

@Overrideprotected void onmeasure (int widthmeasurespec, int heightmeasurespec) {//TODO auto-generated method Stubmeasurechildren (Widthmeasurespec, Heightmeasurespec); Super.onmeasure (Widthmeasurespec, heightMeasureSpec);}


The use of this method is shown below, here remember to add Measurechildren (Widthmeasurespec, heightmeasurespec); Indicates that the size of each child view is measured by the system itself



3. Add parameters, for example, if we want to have space between sub-view, we need to create an internal parameter class manually

public static class Flowlayoutparams extends Viewgroup.marginlayoutparams{public flowlayoutparams (context context, AttributeSet attrs) {Super (context, attrs);//TODO auto-generated constructor stub}}




4. Rewrite the OnLayout method, set the layout of the child view, this method is also the most critical, it determines the characteristics of your custom layout

@Overrideprotected void OnLayout (boolean arg0, int left, int top, int. right, int bottom) {//TODO auto-generated Method St ub//obtains the width int mviewgroupwidth = Getmeasuredwidth () measured by FlowLayout,/*** Paintx: Draws the horizontal axis of the cursor at the beginning of each view * Painty: The ordinate */int paintx = left;int Painty = top;//is used to record the maximum height of the previous row int maxlineheight = 0;int ChildCount = getchildcount when drawing each view ); for (int i=0; i<childcount; i++) {View Childview = Getchildat (i);//Get the margin parameter for each child View Flowlayout.flowlayoutparams params = (flowlayout.flowlayoutparams) childview.getlayoutparams ();//Get the width and height measured by each sub-view int childviewwidth = Childview.getmeasuredwidth (); int childviewheight = Childview.getmeasuredheight ();//If you draw the beginning horizontal line + Left pitch + child view width + The right spacing is larger than the width of the flowlayout and requires a newline if (Paintx + childviewwidth + params.leftmargin + params.rightmargin> mviewgroupwidth) {/ /Draw the horizontal axis of the starting point back to FlowLayout's horizontal axis Paintx = left;//The ordinate of the starting point of the drawing to move the height of one row down Painty = painty + maxlineheight + params.topmargin + params.bottommargin;maxlineheight = 0;} Maxlineheight = Math.max (Childviewheight, MaxlinEheight); Childview.layout (Paintx+params.leftmargin, Painty+params.topmargin, paintx+childviewwidth+ Params.leftmargin, Painty+childviewheight+params.topmargin);//Every time the cursor is drawn, the starting point is shifted to the right Paintx = paintx + childviewwidth + Params.leftmargin + Params.rightmargin;}}


Parsing: In the OnLayout method, we iterate over each sub-view and set the position they should be in, such as LinearLayout, in the OnLayout system will specify that its sub-view can only be arranged horizontally or vertically, that is to say, the layout of the onlayout lining view is determined by our own thoughts, what is the nature of this custom arrangement?

Here our demo is Custom FlowLayout, that is, each line is aligned to the right, until the line is not enough to accommodate, then the child view automatically wrapped, into the next line , and so on, so as to achieve the flow layout, in order to achieve this effect, The most critical should be in the line, we need to implement so that our sub-view can determine the end of the line, the code is as follows:

1. First, you need to record the width of the flowlayout as the maximum width of each line:

int mviewgroupwidth = Getmeasuredwidth ();



2. Each time a sub-view is drawn, it is done through the View.layout () method, and the layout method needs to provide 4 parameters, i.e. (draw the starting axis, the starting axis of the drawing, the width of the child view, the height of the sub-view), Each sub-view must draw a different starting point, so you need to define two variables to record: Paintx,painty:

/** * Paintx: Draws the horizontal axis of the cursor starting point of each view * Painty: The coordinates of the beginning of the cursor at each view are plotted */int Paintx = left;int Painty = top;




3. With a For loop, you can iterate through each sub-view, so you need to define a margin parameter to give to the child view because there is space between the child view:
Flowlayout.flowlayoutparams params = (flowlayout.flowlayoutparams) childview.getlayoutparams ();


And get the width of each child view:
int childviewwidth = Childview.getmeasuredwidth (); int childviewheight = Childview.getmeasuredheight ();




4. If you add a sub-view again, you need not wrap, so the width of the view and the width of the current line is added, and the width of the flowlayout (that is, the upper limit) is compared, if the upper limit, the line-wrapping operation:

The horizontal axis of the drawn starting point is re-moved back to FlowLayout's horizontal axis Paintx = left;//The ordinate of the starting point of the drawing to move down one line of height Painty = painty + maxlineheight + params.topmargin + params.bottommargin;//the current line becomes the next line because of a newline, the maximum height is naturally set to the height of the child view of the current new row (because it is the first view of the next line) Maxlineheight = Childviewheight;


5. Draw the current sub view and move the cursor to the next start point:

The maximum height of the current row is calculated each time Maxlineheight = Math.max (Childviewheight, maxlineheight); Childview.layout (paintx+ Params.leftmargin, Painty+params.topmargin, Paintx+childviewwidth+params.leftmargin, paintY+childViewHeight+ Params.topmargin);//Every time the cursor is drawn, the starting point is shifted to the right Paintx = paintx + childviewwidth + params.leftmargin + params.rightmargin;



At this point, a basic FlowLayout layout definition is complete and the next step is to use it in the layout file:

<relativelayout xmlns:android= "http://schemas.android.com/apk/res/android" xmlns:tools= "http// Schemas.android.com/tools "android:layout_width=" fill_parent "android:layout_height=" fill_parent "> &L        T;com.example.view.flowlayout android:layout_width= "fill_parent" android:layout_height= "Fill_parent" >    <button android:layout_width= "wrap_content" android:layout_height= "wrap_content" android:text= "All" /> <button android:layout_width= "wrap_content" android:layout_height= "Wrap_content" android:text= " Sports "/> <button android:layout_width=" wrap_content "android:layout_height=" Wrap_content "Android: Text= "TV series"/> <button android:layout_width= "wrap_content" android:layout_height= "Wrap_content" a ndroid:text= "Zongyi"/> <button android:layout_width= "wrap_content" android:layout_height= "Wrap_content" "android:text=" movie "/> <button         Android:layout_width= "Wrap_content" android:layout_height= "wrap_content" android:text= "funny"/> <     Button android:layout_width= "wrap_content" android:layout_height= "wrap_content" android:text= "Children's education"/>    <button android:layout_width= "wrap_content" android:layout_height= "wrap_content" android:text= "Technical Tutorials" /> <button android:layout_width= "wrap_content" android:layout_height= "Wrap_content" Android:text = "Music channel"/> <button android:layout_width= "wrap_content" android:layout_height= "Wrap_content" Android Oid:text= "Live Event"/> </com.example.view.FlowLayout></RelativeLayout>



Run:




We can see that we have achieved the desired effect, but the size of the FlowLayout we set here is fill_parent, what if we change to wrap_content ?
Set FlowLayout's layout_height to wrap_content, although the screen still renders the same effect, but in the preview window, click FlowLayout, you can see that FlowLayout is still Fill_ The size of the parent, not the edge of the child view ,



This is not the effect we want, the correct approach should be: When set to Wrap_content,the flowlayout boundary is tightly attached to the edge of the child view , so we should modify the onmeasure method:

@Overrideprotected void onmeasure (int widthmeasurespec, int heightmeasurespec) {//TODO auto-generated method stub// Measurechildren (Widthmeasurespec, Heightmeasurespec); Super.onmeasure (Widthmeasurespec, heightMeasureSpec);// Get FlowLayout mode and wide-high int widthmode = Measurespec.getmode (widthmeasurespec); int widthsize = Measurespec.getsize ( WIDTHMEASURESPEC); int heightmode = Measurespec.getmode (heightmeasurespec); int heightsize = Measurespec.getsize ( HEIGHTMEASURESPEC);//Record wrap_content under the final width and height int width = 0;int height = 0;//record the maximum width and maximum height of each row int linewidth = 0;int Lineheight = 0;int ChildCount = Getchildcount (); for (int i=0;i<childcount;i++) {View Childview = Getchildat (i); Measurechild (Childview, Widthmeasurespec, Heightmeasurespec); Flowlayout.flowlayoutparams params = (flowlayout.flowlayoutparams) childview.getlayoutparams (); int childWidth = Params.leftmargin + childview.getmeasuredwidth () + params.rightmargin;int childheight = Params.topMargin + Childview.getmeasuredheight () + params.bottommargin;//If the line is wrapped, the width of the current row is compared to the width of the next child view, the largest person temporarily as the width of the FlowLayout if (linewidth + childwidth > widthsize) {width = Math.max ( LineWidth, Childwidth); Height = height + lineheight;linewidth = childwidth;lineheight = Childheight;}                  else//Otherwise accumulative value Linewidth,lineheight Maximum height {linewidth + = Childwidth;          Lineheight = Math.max (lineheight, childheight);                  }//If it is the last child viewif (i = = childCount-1) {width = Math.max (width, linewidth);              Height + = lineheight; }//depends on the pattern to determine the size of the FlowLayout, if not exactly, then the pattern set in the layout file should be wrap_content/*** if it is wrap_content, Then set the FlowLayout width and height to the final width we calculated * If it is a fill_parent or a specific value, set the FlowLayout width and height to the beginning GetMode and GetSize get the width of the height */ Setmeasureddimension (Widthmode = = measurespec.exactly)? widthsize:width, (Heightmode = = Measurespec.exac TLY)? Heightsize:height); }



Review the preview window again:



About rewriting the system control will be in the future blog post integration, I hope this article will allow you to customize the ViewGroup help.

Android in layman's custom control (ii)

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.