50 Android Development Tips (03 self-defined ViewGroup)

Source: Internet
Author: User

question: How do you create a layout that you see, for example?

Figure 1
(Original address: http://blog.csdn.net/vector_yi/article/details/24415537)
you might say that usingRelativelayout and Marginscan be achieved. Indeed, for example, the following XML code can easily build a similar layout:
<relativelayout xmlns:android = "http://schemas.android.com/apk/res/android"    android:layout_width= "Fill_ Parent "    android:layout_height=" fill_parent ">    <view        android:layout_width =" 100DP "        android: Layout_height = "150DP"        android:background = "#FF0000"/>    <view        android:layout_width = "100DP"        Android:layout_height = "150DP"        android:layout_marginleft = "30DP"        android:layout_margintop = "20DP"        Android:background = "#00FF00"/>    <view        android:layout_width = "100DP"        android:layout_height = " 150DP "        android:layout_marginleft =" 60DP "        android:layout_margintop =" 40DP "        android:background =" # 0000FF "/></relativelayout>
Effect 2:

Figure 2
However, when encountering complex, variable-like layouts, the use of margins may seem cumbersome. Here we look at another way to create a similar layout---Define yourself ViewGroupThe advantages include the following points:
    • Easier maintenance When you apply this layout to different activity
    • Ability to define each of the sub-view in ViewGroup by using its own defined attributes
    • More concise and readable XML file content
    • Suppose you need to change the margin. There is no need to manually calculate the margin for each sub-view
first, understand the steps of Android to draw a viewthe steps for drawing a view. To see the official Android Documentation: http://developer.android.com/guide/topics/ui/how-android-draws.htmlHere, we focus on the ViewGroup drawing process: 1. Handle the width and height of the viewgroup. Handling of width and height is done in the Onmeasure () method, within this method.          The ViewGroup calculates the layout space occupied by itself based on its child view. 2. Layout to page this is done in the OnLayout () method, where ViewGroup draws each of its child view based on the information obtained from the Onmeasure ().


Ii. Construction of Cascadelayout classFirst add the cascadelayout to the XML layout file:
<framelayout <!--define the namespace yourself so that you can use the properties that you define later in this article-Xmlns:cascade = "http://schemas.android.com/apk/res/ com.manning.androidhacks.hack003 "xmlns:android=" Http://schemas.android.com/apk/res/android "Android:layout_ Width= "Fill_parent" android:layout_height= "fill_parent" > <com.manning.androidhacks.hack003.view.cascadelay Out android:layout_width = "fill_parent" android:layout_height = "Fill_parent" Cascade:horizontal_spaci            ng = "30DP" <!--because the Cascade namespace was added earlier, it is possible to use its own definition property--cascade:vertical_spacing = "20DP" > <view Android:layout_width = "100DP" android:layout_height = "150DP" cascade:layout_vertical_spacing = "90DP" <!--its own defined properties for child View, which will be used in the third part of this document--Android:background = "#FF0000"/> <view A        Ndroid:layout_width = "100DP" android:layout_height = "150DP" Android:background = "#00FF00"/> <view Android:layout_width = "100DP" android:layout_height = "150DP" Android:background = "#0000FF"/> </com.manning.an Droidhacks.hack003.view.cascadelayout></framelayout>
To use these properties of your own definition, we need to define it.

Create a Attrs.xml file under the Res/values directory:
<? XML version = "1.0" encoding= "Utf-8"?><resources>    <declare-styleable name= "Cascadelayout" >        <attr name= "horizontal_spacing" format = "Dimension"/>        <attr name= "vertical_spacing" format = "Dimension" />    </declare-styleable></resources>
and then. A default value is required when we create cascadelayout and do not specify horizontal_spacing and vertical_spacing for it.

We pre-define this default value and store it in the Dimens.xml in the Res/values directory:
<?

XML version = "1.0" encoding= "Utf-8"?

><resources> <dimen name= "cascade_horizontal_spacing" >10dp</dimen> <dimen name= " Cascade_vertical_spacing ">10dp</dimen></resources>

Finally, we need to create a Java class named Cascadelayout. It inherits ViewGroup and re-writes the Onmeasure () and OnLayout () methods. Constructors for 1.CascadeLayout
Public Cascadelayout (context context, AttributeSet Attrs) {    Super (context, attrs);    TypedArray A = context. Obtainstyledattributes (Attrs,        R. styleable. Cascadelayout);    try {      mhorizontalspacing = A. Getdimensionpixelsize (          R. styleable. Cascadelayout_horizontal_spacing,          getresources (). Getdimensionpixelsize (              R. dimen. Cascade_horizontal_ spacing));      Mverticalspacing = A. Getdimensionpixelsize (          R. styleable. Cascadelayout_vertical_spacing, Getresources ()              . Getdimensionpixelsize (r. dimen. cascade_vertical_spacing)); c11/>} finally {      A. recycle ();    }
2. Build your own defined Layoutparams classThe Layoutparams class will exist as the inner class of the cascadelayout, which will store the x for each child view. The y-coordinate. Definitions such as the following:
public static class Layoutparams extends ViewGroup. layoutparams {    int x;    int y;    Public Layoutparams (context context, AttributeSet Attrs) {      Super (context, attrs);    }    Public Layoutparams (int w, int h) {      super (W, h);    }  }

3. Overriding the Onmeasure () methodThe onmeasure () method will be the most critical part of the Cascadelayout class, which calculates not only the layout space occupied by the entire viewgroup. The layout space occupied by each child view is also calculated.
@Override  protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {    int width = 0;    int height = getpaddingtop ();    Final int count = Getchildcount ();    for (int i = 0; i < count; i++) {      View child = Getchildat (i);      Measurechild (Child, Widthmeasurespec, Heightmeasurespec);       Layoutparams LP = (layoutparams) child. Getlayoutparams ();      width = getpaddingleft () + mhorizontalspacing * i;      LP. x = width;      LP. y = height;      width + = child. Getmeasuredwidth ();      Height + = mverticalspacing;    }    width + = getpaddingright ();    Height + = Getchildat (Getchildcount ()-1). Getmeasuredheight ()        + Getpaddingbottom ();    Setmeasureddimension (resolvesize (width, widthmeasurespec),        resolvesize (height, heightmeasurespec));  }

4. Last step, rewrite the OnLayout () methodThe code is very easy, which is to have each child view call the layout () method.
@Override  protected void OnLayout (Boolean changed, int l, int t, int r, int b) {    final int count = Getchildco UNT ();    for (int i = 0; i < count; i++) {      View child = Getchildat (i);      Layoutparams LP = (layoutparams) child. Getlayoutparams ();      Child. Layout (LP. x, LP. Y, LP. x +. Getmeasuredwidth (), LP. Y          + child. Getmeasuredheight ());}  }

At this point , a layout page with the same effect as Figure 2 was created with the viewgroup of your own definition.


third, to add their own definition of properties for child view
now that you've had so much effort, how could it be the same as the previous few lines of XML code? below, let's add ourselves to define the attributes for the child view in Cascadelayout:First, add the following code to the Attrs.xml that you created earlier:
<declare-styleable name= "Cascadelayout_layoutparams" >     <attr name= "layout_vertical_spacing" format= " Dimension "/></declare-styleable>
because this newly added attribute starts with Layout_. So it's going to be added to the layoutparams. we were able to read this property in the constructor in the previously defined inner class layoutparams, changing the first constructor to:
Public Layoutparams (context context, AttributeSet Attrs) {      Super (context, attrs);      TypedArray A = context. Obtainstyledattributes (Attrs,          R. styleable. Cascadelayout_layoutparams);      try {        verticalspacing = a            . Getdimensionpixelsize (                R. styleable. Cascadelayout_layoutparams_layout_vertical_spacing,                -1);      } finally {        A. recycle ();      }    }

now that you have added a new self-defined attribute. It must be dealt with in the Onmeasure () method:
@Override protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {int width = getpaddingleft ();    int height = getpaddingtop ();    int verticalspacing;    Final int count = Getchildcount ();      for (int i = 0; i < count; i++) {verticalspacing = mverticalspacing;      View child = Getchildat (i);      Measurechild (Child, Widthmeasurespec, Heightmeasurespec);      Layoutparams LP = (layoutparams) child. Getlayoutparams ();      width = getpaddingleft () + mhorizontalspacing * i;      LP. x = width;      LP. y = height;      if (LP. Verticalspacing >= 0) {verticalspacing = LP. Verticalspacing;      } width + = child. Getmeasuredwidth ();    Height + = verticalspacing;    } width + = Getpaddingright (); Height + = Getchildat (Getchildcount ()-1).    Getmeasuredheight () + Getpaddingbottom ();  Setmeasureddimension (resolvesize (width, widthmeasurespec), resolvesize (height, heightmeasurespec)); }



Finally, the complete Cascadelayout code is attached:
Package Com.manning.androidhacks.hack003.view;import Android.content.context;import Android.content.res.typedarray;import Android.util.attributeset;import Android.view.view;import  Android.view.viewgroup;import Com.manning.androidhacks.hack003.r;public class Cascadelayout extends ViewGroup {  private int mhorizontalspacing;  private int mverticalspacing;    Public Cascadelayout (context context, AttributeSet Attrs) {Super (context, attrs);    TypedArray a = Context.obtainstyledattributes (Attrs, r.styleable.cascadelayout); try {mhorizontalspacing = A.getdimensionpixelsize (r.styleable.cascadelayout_horizontal_spacing, G      Etresources (). Getdimensionpixelsize (r.dimen.cascade_horizontal_spacing));              mverticalspacing = A.getdimensionpixelsize (r.styleable.cascadelayout_vertical_spacing, GetResources ()    . Getdimensionpixelsize (r.dimen.cascade_vertical_spacing));    } finally {a.recycle (); }} @Override protected VOID onmeasure (int widthmeasurespec, int heightmeasurespec) {int width = getpaddingleft ();    int height = getpaddingtop ();    int verticalspacing;    Final int count = Getchildcount ();      for (int i = 0; i < count; i++) {verticalspacing = mverticalspacing;      View child = Getchildat (i);      Measurechild (Child, Widthmeasurespec, Heightmeasurespec);      Layoutparams LP = (layoutparams) child.getlayoutparams ();      width = getpaddingleft () + mhorizontalspacing * i;      lp.x = width;      lp.y = height;      if (lp.verticalspacing >= 0) {verticalspacing = lp.verticalspacing;      } width + = Child.getmeasuredwidth ();    Height + = verticalspacing;    } width + = Getpaddingright ();    Height + = Getchildat (Getchildcount ()-1). Getmeasuredheight () + Getpaddingbottom ();  Setmeasureddimension (resolvesize (width, widthmeasurespec), resolvesize (height, heightmeasurespec)); } @Override protected void OnLayout (Boolean changed, int l, int t, int R, int b) {Final int count = Getchildcount ();      for (int i = 0; i < count; i++) {View child = Getchildat (i);      Layoutparams LP = (layoutparams) child.getlayoutparams ();    Child.layout (lp.x, lp.y, lp.x + child.getmeasuredwidth (), Lp.y + child.getmeasuredheight ());  }} @Override protected Boolean checklayoutparams (Viewgroup.layoutparams p) {return P instanceof layoutparams;         } @Override protected Layoutparams generatedefaultlayoutparams () {return new Layoutparams (Layoutparams.wrap_content,  Layoutparams.wrap_content); } @Override Public Layoutparams generatelayoutparams (AttributeSet attrs) {return new Layoutparams (GetContext (), attr  s); } @Override protected Layoutparams generatelayoutparams (Viewgroup.layoutparams p) {return new Layoutparams (P.width,  P.height);    } public static class Layoutparams extends Viewgroup.layoutparams {int x;    int y;    public int verticalspacing; Public Layoutparams (context context, AttrIbuteset attrs) {Super (context, attrs);      TypedArray a = Context.obtainstyledattributes (Attrs, r.styleable.cascadelayout_layoutparams); try {verticalspacing = a. Getdimensionpixelsize (R.styleable.cascadelayout_layoutparams_      Layout_vertical_spacing,-1);      } finally {a.recycle ();    }} public Layoutparams (int w, int h) {super (W, h); }  }}

Project folder structure:


(original address: http://blog.csdn.net/vector_yi/article/details/24415537)


50 Android Development Tips (03 self-defined ViewGroup)

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.