The Android custom control inherits ViewGroup create a new container _android

Source: Internet
Author: User
Tags int size xmlns

You are welcome to learn this section and we have learned several other custom controls in the previous sections. is the andriod of the custom control and the creation of the Andriod custom control. Composite controls that can be reused the students who have not yet learned please go to study, as this section will use the content described in the previous sections.

Before we learn new content, let's find out two things:

1. What is ViewGroup?

ViewGroup is a kind of container. It contains 0 or more view and child view.

2. What's the role of ViewGroup?

ViewGroup can be used to hold multiple view controls and to measure the view child control based on its own measurement pattern, and to determine the position of the view child control. This step-by-step explains how it measures and determines the size and location of the child controls.

OK, to figure out these two problems, then let's study the custom ViewGroup.

First, as in previous sections, you inherit ViewGroup and override their construction methods.

public class Customviewgroup extends viewgroup{the public
 customviewgroup (context context) {This
 (context,null);
 }

 Public Customviewgroup (context, AttributeSet attrs) {This
 (context, attrs,0);
 }

 Public Customviewgroup (context, AttributeSet attrs, int defstyleattr) {
 Super (context, Attrs, defstyleattr );
 }
}

In the above two questions, we know that ViewGroup is a container that is used to store and manage child controls, and that the child controls are measured in terms of its measurement pattern, so we have to rewrite its onmeasure () to measure the size of the view in the method. The code is as follows:

 @Override
 protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {
 super.onmeasure ( Widthmeasurespec, Heightmeasurespec);
 int childcount = Getchildcount ();
 for (int i = 0; i < ChildCount i + +) {
  View children = Getchildat (i);
  Measurechild (CHILDREN,WIDTHMEASURESPEC,HEIGHTMEASURESPEC);
 }
 

On the code, we rewrite the Onmeasure (), in the method, we first get the number of child view in the ViewGroup, and then iterate through all of its child view, get each child view, call Measurechild () to put, to measure the view. The measurement of the child view is based on the measurement pattern provided by ViewGroup, so in the Measurechild () method, the ViewGroup Widthmeasurespec and Heightmeasurespec and son view together, we can go in to see if it is the same as we said.

Measurechild () method source code:

 protected void Measurechild (View child, int parentwidthmeasurespec,
  int parentheightmeasurespec) {
 final Layoutparams LP = Child.getlayoutparams ();

 Final int childwidthmeasurespec = Getchildmeasurespec (Parentwidthmeasurespec,
  mpaddingleft + mpaddingright, Lp.width);
 Final int childheightmeasurespec = Getchildmeasurespec (Parentheightmeasurespec,
  mpaddingtop + MPaddingBottom, Lp.height);

 Child.measure (Childwidthmeasurespec, Childheightmeasurespec);
 }

The Measurechild () source method is well understood, it first obtains the layoutparams of the child view, and then according to ViewGroup Pass in the wide high attribute value and its own layoutparams The Getchildmeasurespec () method is used to obtain the measurement of the child view by calling the width-high attribute value and its own padding property value respectively. It is also known from this method that the measurement results are determined by the measurement mode of the parent node and the layoutparams and padding of the child view itself, when the size of the viewgroup is measured.

Let's take a look at the source code of the Getchildmeasurespec () method to see how it obtains the measurement results.

Getchildmeasurespec () method source code:

 public static int Getchildmeasurespec (int spec, int padding, int childdimension) {int specmode = Measurespec.getmode (s
 PEC);

 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) {//child wants 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 s
  Pecific 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; Parent asked to [how do we want to is case MeasureSpec.UNSPECIFIED:if (childdimension >= 0) {//child WAN
  TS a specific 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 ... how do I//big it should be resultsize = View.susezerounspecifiedmeasurespec?
  0:size;
  Resultmode = measurespec.unspecified;
 } break;
 Return Measurespec.makemeasurespec (resultsize, Resultmode);

 }

The method is also well understood: the first is to get the measurement mode and measurement size of the parent node (here is ViewGroup), and to obtain a size value based on the measured size value compared with the Padding property value of the child view itself.
Then the Layoutparams attribute value of the child view is determined according to the measurement mode of the parent node, and the size and mode of the view measurement are obtained according to the Layoutparams attribute value, and the Ziview measurement mode and size can determine the size of the child view.

OK, the measurement of the child view we have fully understood, then next, we will analyze how viewgroup to the child view positioning, first of all, we must first rewrite the OnLayout () method, the code is as follows:

@Override
 protected void OnLayout (Boolean changed, int l, int t, int r, int b) {
 int childcount = Getchildcount ();
 int preheight = 0;
 for (int i = 0; i < ChildCount i + +) {
  View children = Getchildat (i);
  int cheight = Children.getmeasuredheight ();
  if (children.getvisibility ()!= view.gone) {
  children.layout (L, preheight, r,preheight = = Cheight);}}
 

Well understood, to position the child view, you first have to know how many view is there, so we first get the number of child view, and then iterate through the fetch for each child view. In fact, in the positioning of the layout () method, the system does not give a specific positioning method, but gave us the maximum limit to define their own, the following layout source code:

public void layout (int l, int t, int r, int b) {if (MPRIVATEFLAGS3 & Pflag3_measure_needed_before_layout)!= 0) {
  Onmeasure (Moldwidthmeasurespec, Moldheightmeasurespec);
 MPRIVATEFLAGS3 &= ~pflag3_measure_needed_before_layout;
 int OLDL = Mleft;
 int Oldt = Mtop;
 int oldb = Mbottom;

 int oldr = 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<onlayoutchangelistener>) Li.mOnLayoutChangeListeners.clone ();
  int numlisteners = Listenerscopy.size (); for (int i = 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;

 }

In the above code, the key is Setframe (L, T, R, b); In this method, it is primarily to locate the left and right coordinates of the four vertices of the child view, and then the key positioning method is in onlayout (changed, L, T, R, b); In this method, follow it.

 protected void OnLayout (Boolean changed, int left, int. top, int right, int bottom) {
 }

A look startled, empty, haha, this is what I said above, the system gives us the greatest freedom, let us define according to the needs.
And I'm here to arrange them in a vertical order based on the height of the child view.

 View children = Getchildat (i);
 int cheight = Children.getmeasuredheight ();
 if (children.getvisibility ()!= view.gone) {
 children.layout (L, preheight, r,preheight + = cheight);

Define a variable that records the height of the previous view, each time it is followed by the current view height, so that each child view can be arranged vertically, thus enabling the definition of the child view.

OK, so much, now to see the effect, let's take the custom view we made before as its child view bar:

Custom_viewgroup.xml file:

<?xml version= "1.0" encoding= "Utf-8"?> <com.sanhuimusic.mycustomview.view.customviewgroup android: Background= "#999999" xmlns:android= "http://schemas.android.com/apk/res/android" xmlns:custom= "http:// Schemas.android.com/apk/res-auto "android:id=" @+id/customviewgroup "android:layout_width=" Match_parent "Android: layout_height= "Match_parent" > <com.sanhuimusic.mycustomview.view.compositeviews android:background= "# 999999 "android:id=" "@+id/topbar" android:layout_width= "wrap_content" android:layout_height= "wrap_content" Custom: titletext= "@string/titletext" custom:titlecolor= "#000000" custom:titletextsize= "@dimen/titletextsize" Custom: Titlebackground= "#999999" custom:lefttext= "@string/lefttext" custom:lefttextcolor= "#FFFFFF" Custom:leftbackground = "#666666" "custom:lefttextsize=" @dimen/lefttextsize "custom:righttext=" @string/righttext "custom:righttextcolor=" #FFFFFF "custom:rightbackground=" #666666 "custom:righttextsize=" @dimen/righttextsize "/> <com. Sanhuimusic.mycustomview.view.AudioBar android:layout_width= "match_parent" android:layout_height= "Wrap_content"
 /> </com.sanhuimusic.mycustomview.view.CustomViewGroup>

Mainactivity:

public class Mainactivity extends Appcompatactivity {
 private compositeviews topbar;
 Private context Mcontext;
 Private Customviewgroup Mviewgroupcontainer;
 @Override
 protected void onCreate (Bundle savedinstancestate) {
 super.oncreate (savedinstancestate);
 Setcontentview (r.layout.custom_viewgroup);
 Mcontext = this;
 Init ();
 }

 private void Init () {
 Mviewgroupcontainer = (customviewgroup) Findviewbyid (r.id.customviewgroup);
 Topbar = (compositeviews) Findviewbyid (R.id.topbar);
 Topbar.setontopbarclicklistener (New Compositeviews.topbarclicklistener () {
  @Override public
  Void Leftclicklistener () {
  toastutil.maketext (mainactivity.this, "You clicked the Return key", Toast.length_short). Show ();
  @Override public
  void Rightclicklistener () {
  toastutil.maketext (mainactivity.this, "You clicked the Search key", Toast.length_short). Show ();}}


Effect Chart:

Haha, is not every child view according to what we call the vertical order down in turn. Just happy, and then suddenly came up with an idea, learned andriod custom control of the audio bar This article, you will remember when the definition of a new view when we use the layout file is Wrap_content, view is not directly supported, Need our special handling to be able to support correctly, and our present viewgroup is not also like this, quickly try. A try, bad, sure enough not to support wrap_content.

Therefore, when customizing ViewGroup, we must pay attention to the following issues:

1. ViewGroup must be allowed to support the layout of wrap_content scenarios.
2. You also need to support your own padding properties.

OK, here we go 1.1 points to perfect it.

1. We let IT support wrap_content first.

This requires that we make some of the necessary changes in the Onmeasure () method. Let it support its own wrap_content that's what we need to wake up to. Measure, obtain the measurement size according to the measurement, and then call Setmeasureddimension () to determine the display size.

@Override protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {super.onmeasure (Widthmeasurespec, Hei
 GHTMEASURESPEC);
 int childcount = Getchildcount ();
  for (int i = 0; i < ChildCount i + +) {View children = getchildat (i);
 Measurechild (CHILDREN,WIDTHMEASURESPEC,HEIGHTMEASURESPEC);
 /** * Let IT support itself wrap_content/int widthspecmode = Measurespec.getmode (Widthmeasurespec);
 int widthspecsize = measurespec.getsize (Widthmeasurespec);
 int heightspecmode = Measurespec.getmode (Heightmeasurespec);
 int heightspecsize = measurespec.getsize (Heightmeasurespec);
 int mwidth = 0;
 int mheight = 0;
 int mmaxwidth = 0; if (Widthspecmode = = Measurespec.at_most && Heightspecmode = = measurespec.at_most) {for (int i = 0; i < CHILDC Ount;
  i + +) {View children = getchildat (i);
  Mwidth + + children.getmeasuredwidth ();
  Mheight + + children.getmeasuredheight ();
 } setmeasureddimension (Mwidth, mheight); else if (Widthspecmode = = Measurespec.at_most) {for (int i = 0; i < ChildCount i + +) {View children = getchildat (i);
  Mmaxwidth = Math.max (Mmaxwidth,children.getmeasuredwidth ());
 } setmeasureddimension (Mmaxwidth,heightspecsize); else if (Heightspecmode = = Measurespec.at_most) {for (int i = 0; i < ChildCount i + +) {View children = Getchilda
  T (i);
  Mheight + + children.getmeasuredheight ();
 } setmeasureddimension (Widthspecsize,mheight);

 }
 }

We add the code that can support Wrap_content on the original basis, and then get the size according to the specific situation. Divided into three kinds of situations:

    • When the width and height attributes are wrap_content, the width of the child view is obtained and the total width is added, and the Setmeasureddimension (Mwidth, Mheight) is set directly.
    • When the width attribute is wrap_content, the width of the child view is obtained and the maximum value is obtained, and the Setmeasureddimension (Mmaxwidth,heightspecsize) is set directly.
    • When the high attribute is wrap_content, the height of the child view is obtained and the total height is added, and the Setmeasureddimension (Widthspecsize,mheight) is set directly.

OK, let's see if we can meet our requirements.

It is clear that the goal has been achieved.

2. You need to support your own padding properties.

First we'll get the padding value, as follows:

leftpadding = Getpaddingleft ();
toppadding = Getpaddingtop ();
rightpadding = Getpaddingright ();
bottompadding = Getpaddingbottom ();

The values of these properties are then added to the set size, as follows:

 if (Widthspecmode = = Measurespec.at_most && Heightspecmode = = Measurespec.at_
  MOST) {for (int i = 0; i < ChildCount i + +) {View children = getchildat (i);
  Mwidth + + children.getmeasuredwidth ();
  Mheight + + children.getmeasuredheight ();
 } setmeasureddimension (Mwidth + leftpadding + rightpadding, Mheight + toppadding + bottompadding); else if (Widthspecmode = = Measurespec.at_most) {for (int i = 0; i < ChildCount i + +) {View children = Getchildat
  (i);
  Mmaxwidth = Math.max (Mmaxwidth,children.getmeasuredwidth ());
 } setmeasureddimension (Mmaxwidth + leftpadding + rightpadding, heightspecsize + toppadding + bottomPadding); else if (Heightspecmode = = Measurespec.at_most) {for (int i = 0; i < ChildCount i + +) {View children = Getchilda
  T (i);
  Mheight + + children.getmeasuredheight ();
 } setmeasureddimension (widthspecsize + leftpadding + rightpadding, Mheight + toppadding + bottompadding); }

Finally, add the property value in the OnLayout () method:

@Override
 protected void OnLayout (Boolean changed, int l, int t, int r, int b) {
 int childcount = Getchildcount ();
 int preheight = toppadding;
 for (int i = 0; i < ChildCount i + +) {
  View children = Getchildat (i);
  int cheight = Children.getmeasuredheight ();
  if (children.getvisibility ()!= view.gone) {
  children.layout (l + leftpadding, Preheight, R + rightpadding, PreHeight + = Cheight);
  }
 }
 

The code is very simple, no longer let Preheight = 0, but directly set to toppadding, and finally in layout also add property values, see the results.

In fact, in addition to the above two issues to pay attention to, there are other also need to pay attention to, for example, support the margin properties of the child view, roughly and solve the padding attribute the same idea, we can try to achieve under.

Well, the entire custom ViewGroup is finished, and of course we're just talking about the UI display and not talking about adding and implementing the feature. As you can see from the above, a custom viewgroup is a lot more complicated than a custom view, but it can be implemented in a step-by-step way or a different UI display.

From these sections, custom control learning, you must have learned a lot of knowledge, and then the custom control is not so afraid, but also to achieve the various UI you want, and then I will summarize the custom control in the use of other technologies and knowledge, so that everyone better to deepen the impression.

All right, let's learn how to get here today, happy!.

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

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.