Implementation of custom ViewGroup in Android

Source: Internet
Author: User

Several common ViewGroup implementations are available in Android, including LinearLayout, Relativeayout, Framelayout, and more. These viewgroup can meet our general development needs, but for the complexity of the interface requirements, these layouts are stretched. So custom viewgroup are ubiquitous in the applications we've been exposed to.

To implement a custom viewgroup, the first step is to learn to customize the properties that will allow us to configure the layout file more flexibly. A custom property is a Attrs.xml file declared under the value directory.

<?xml version= "1.0"  encoding= "Utf-8"? ><resources>    <declare-styleable name= "CascadeViewGroup" >         <attr name= "verticalspacing"  format= "Dimension"/>         <attr name= "horizontalspacing"  format= "Dimension" />    </declare-styleable>    <declare-styleable name = "Cascadeviewgroup_layoutparams" >        <attr name= "layout _paddingleft " format=" Dimension "/>        <attr name=" Layout_paddintop " format=" Dimension "/>    </declare-styleable></resources 

Here we declare two custom attribute sets, the properties in Cascadeviewgroup are set for our custom Cascadeviewgroup component, that is, the layout file can be <CascadeViewGroup> The properties that can be used in the label. The other cascadeviewgroup_layoutparams is the property that is set for the child view in Cascadeviewgroup.

Before writing the code, we also set a default width and height for cascadelayout to use. These two properties are defined in Dimens.xml.

<?xml version= "1.0" encoding= "Utf-8"?><resources> <dimen name= "default_horizontal_spacing" >10dp& lt;/dimen> <dimen name= "default_vertical_spacing" >10dp</dimen></resources>


The following is the beginning of writing custom component Cascadelayout.

package com.app.customviewmotion;import android.content.context;import  Android.content.res.typedarray;import android.util.attributeset;import android.view.view;import  android.view.viewgroup;/** * created by charles on 2015/8/13. */ public class cascadeviewgroup extends viewgroup {    // Customize the width and height set in the layout     private int mhoriztonalspacing;    private  int mverticalspacing;    public cascadeviewgroup (Context context)  {        this (context, null);     }     public cascadeviewgroup (context context, attributeset attrs)   {        this (context, attrs, 0);     }     public cascadeviewgroup (context  context, attributeset attrs, int defstyle)  {         super (Context, attrs, defstyle);         Typedarray a = context.obtainstyledattributes (Attrs, r.styleable.cascadeviewgroup);         try {             //get the width of the setting              Mhoriztonalspacing = a.getdimensionpixelsize (r.styleable.cascadeviewgroup_horizontalspacing,                      this.getresources (). Getdimensionpixelsize (r.dimen.default_horizontal_spacing));             //get the height of settings              mverticalspacing =&Nbsp;a.getdimensionpixelsize (r.styleable.cascadeviewgroup_verticalspacing,                     this.getresources (). Getdimensionpixelsize (r.dimen.default_vertical_spacing));         }  catch  (exception e)  {             e.printstacktrace ();        } finally {             a.recycle ();         }    }     @Override     protected  Void onmeasure (Int widthmeasurespec, int heightmeasurespec)  {         final int count = this.getchildcount ();         int&nbSp;width = this.getpaddingleft ();         int height  = this.getpaddingtop ();        for  (int i =  0; i < count; i++)  {             final view currentview = this.getchildat (i);             this.measurechild (currentview, widthmeasurespec,  HEIGHTMEASURESPEC);             cascadeviewgroup.layoutparams lp =  (cascadeviewgroup.layoutparams)   Currentview.getlayoutparams ();             if ( lp.msettingpaddingleft != 0) {                 width +=lp.msettingpaddingleft;            }             if (lp.msettingpaddingtop != 0) {                 height +=lp.mSettingPaddingTop;             }             lp.x = width;             lp.y = height;             width += mhoriztonalspacing;             height += mverticalspacing;        }         width +=getchildat (This.getchildcount ()  - 1). GetMeasuredWidth ()  +  this.getpaddingright ();         height += getchildat (This.getChildCount ()  -  1). Getmeasuredheight ()  + this.getpaddingbottom ();         this.setmeasureddimension (Resolvesize (Width, widthmeasurespec),  resolvesize (height,  HEIGHTMEASURESPEC));    }     @Override      Protected void onlayout (boolean b, int l, int i1, int i2,  INT&NBSP;I3)  {        final int count =  This.getchildcount ();        for  (int i = 0;  i < count; i++)  {             final view currentview = this.getchildat (i);             cascadeviewgroup.layoutparams lp =  (Cascadeviewgroup.layoutparams)  currentview.getlayoutparams ();             currentview.layout (LP.X,&NBSP;LP.Y,  lp.x + currentview.getmeasuredwidth (),                     lp.y +  Currentview.getmeasuredheight ());         }    }     public static class LayoutParams extends  viewgroup.layoutparams {        int x;         int y;        int  msettingpaddingleft;        int msettingpaddingtop;         public layoutparams (Context c, aTtributeset attrs)  {            super (c, &NBSP;ATTRS);             typedarray a =  c.obtainstyledattributes (Attrs, r.styleable.cascadeviewgroup_layoutparams);             msettingpaddingleft = a.getdimensionpixelsize ( r.styleable.cascadeviewgroup_layoutparams_layout_paddingleft, 0);             msettingpaddingtop = a.getdimensionpixelsize ( r.styleable.cascadeviewgroup_layoutparams_layout_paddintop, 0);             a.recycle ();        }         public layoutparams (int width, int height)  {         &nbsP;   super (width, height);        }         public layoutparams (Viewgroup.layoutparams source)  {             super (source);         }    }     @Override     protected  viewgroup.layoutparams generatedefaultlayoutparams ()  {         return new layoutparams (layoutparams.wrap_content, layoutparams.wrap_content);     }     @Override     protected  Viewgroup.layoutparams generatelayoutparams (viewgroup.layoutparams p)  {         return new layoutparams (P);    }     @Override     pubLic viewgroup.layoutparams generatelayoutparams (attributeset attrs)  {         return new layoutparams (This.getcontext (),  attrs);     }}

The code has a slight advantage, but the structure is still very clear.

1) Construct the value of the configuration property in the method or in the XML file. Use the methods in Typedarray to get the properties that we set in layout layouts, and save them in member variables.

2) constructs the custom inner class layoutparams. Constructing this inner class allows us to save their property values when we measure our sub-view so that they can be laid out in the layout stage.

3) Generatelayoutparams (), Generatedefaultparams () and other methods. In these methods, we return our custom layoutparams. As for why to rewrite these methods, it is clear that you can see the AddView () method of the ViewGroup class.

4) Measure stage. In the measure phase, we measure our size, and we also measure the size of the sub-view and save the Child View information in Layoutparams.

5) Layout stage. Layout their locations based on the information of each child view.


Finally, add the layout file.

<?xml version= "1.0"  encoding= "Utf-8"?><!--Add custom properties to viewgroup--><!-- The suffix of the newly added namespace must remain consistent with the package name declared in the. xml--><com.app.customviewmotion.cascadeviewgroup         xmlns:android= "Http://schemas.android.com/apk/res/android"          xmlns:ts= "Http://schemas.android.com/apk/res/com.app.CustomViewMotion"          android:layout_width= "Match_parent"          android:layout_height= "Match_parent"         ts:horizontalspacing = "15DP"         ts:verticalspacing= "15DP" >     <textview android:layout_width= "100DP"                android:layout_height= "100DP"                android:gravity= "Center "              android:text=" Text1 "               android:background= "# 668b8b "/>    <textview android:layout_width=" 100DP "               android:layout_height= "100DP"                android:gravity= "Center"                android:text= "Text2"                android:background= "#FFDAB9"/>     <textview android:layout_width= "100DP"                android:layout_height= "100DP"                android:gravity= "Center"                android:text= "Text3"                Android:background= "#43CD80"/>< Add custom sub-view properties to this child view-->    <textview  Android:layout_width= "100DP"                android:layout_height= "100DP"                android:gravity= "Center"                android:text= "Text4"                ts:layout_paddingleft= "100DP"                ts:layout_paddintop= "100DP"                android:backgroUnd= "#00CED1"/></com.app.customviewmotion.cascadeviewgroup> 


The effect of the implementation is as follows:


Implementation of custom ViewGroup in Android

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.