Look at the code first.
First, view Natsume
1. Custom Controls
public class Customviewgroup extends ViewGroup {... @Override protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {super.onmeasure (Widthmeasurespec, Heightmeasurespec); Traverse all sub-views for Measure operation for (int i = 0; i < Getchildcount (); i++) {View child = Getchildat (i); if (child! = null && child.getvisibility ()! = View.gone) {measurechild (Child, Widthmeasuresp EC, HEIGHTMEASURESPEC); Android:layout_margin properties that support child view settings marginlayoutparams Layoutparams = (marginlayoutparams) child.getlayoutpa Rams (); int marginleft = Layoutparams.leftmargin; }} setmeasureddimension (Widthmeasurespec, Heightmeasurespec); } @Override protected void OnLayout (Boolean changed, int left, int top, int. right, Int. bottom) {for (int i = 0; I < Getchildcount (); i++) {View Childview = Getchildat (i);//Only for the simplest code to reproduce the bug, allSub-views are randomly placed childview.layout (left, top, leave + childview.getmeasuredwidth (), Top + childview.getmeasuredheight ()); } }}
Inherited from ViewGroup, mainly demonstrates how to support the margin property in a custom view, focusing on the Child.getlayoutparams () line, and then looking at how the layout file is used
2. Layout files
<com.example.android.apis.customviewgroup android:id= "@+id/custom_view_group" android:layout_width= "Match_parent" android:layout_height= "wrap_content" > <textview android:layout_width= "Wrap_ Content " android:layout_height=" wrap_content "android:layout_margin=" 10dip " android:text=" Love_world_ "/ > </com.example.android.apis.CustomViewGroup>
Plays: android:layout_margin= "10dip" Margin property
3. Exceptions
Java.lang.classcastexception:android.view.viewgroup$layoutparams cannot is cast to android.view.viewgroup$ Marginlayoutparamsat com.example.android.apis.CustomViewGroup.onMeasure (customviewgroup.java:50) at Android.view.View.measure (view.java:16831) at Android.view.ViewGroup.measureChildWithMargins (viewgroup.java:5245 ) at Android.widget.LinearLayout.measureChildBeforeLayout (linearlayout.java:1410) at Android.widget.LinearLayout.measureHorizontal (linearlayout.java:1052) at Android.widget.LinearLayout.onMeasure ( linearlayout.java:590) at Android.view.View.measure (view.java:16831) at Android.view.ViewGroup.measureChildWithMargins (viewgroup.java:5245) at Android.widget.LinearLayout.measureChildBeforeLayout (linearlayout.java:1410) at Android.widget.LinearLayout.measureVertical (linearlayout.java:695) at Android.widget.LinearLayout.onMeasure ( linearlayout.java:588) at Android.view.View.measure (view.java:16831) at Android.view.ViewGroup.measureChildWithMargins (viewgroup.java:5245) at Android.widget.FrameLayoUt.onmeasure (framelayout.java:310) at Android.view.View.measure (view.java:16831) at Android.widget.LinearLayout.measureVertical (linearlayout.java:847) at Android.widget.LinearLayout.onMeasure ( linearlayout.java:588) at Android.view.View.measure (view.java:16831) at Android.view.ViewGroup.measureChildWithMargins (viewgroup.java:5245) at Android.widget.FrameLayout.onMeasure ( framelayout.java:310) at Com.android.internal.policy.impl.phonewindow$decorview.onmeasure (PhoneWindow.java:2586) At Android.view.View.measure (view.java:16831) at Android.view.ViewRootImpl.performMeasure (viewrootimpl.java:2189) At Android.view.ViewRootImpl.measureHierarchy (viewrootimpl.java:1352) at Android.view.ViewRootImpl.performTraversals (viewrootimpl.java:1535) at Android.view.ViewRootImpl.doTraversal ( viewrootimpl.java:1249) at Android.view.viewrootimpl$traversalrunnable.run (viewrootimpl.java:6364) at Android.view.choreographer$callbackrecord.run (choreographer.java:791) at Android.view.Choreographer.doCallbacks ( Choreographer.java:5In Android.view.Choreographer.doFrame (choreographer.java:561) at android.view.choreographer$ Framedisplayeventreceiver.run (choreographer.java:777) at Android.os.Handler.handleCallback (handler.java:730) at Android.os.Handler.dispatchMessage (handler.java:92) at Android.os.Looper.loop (looper.java:176) at Android.app.ActivityThread.main (activitythread.java:5419) at java.lang.reflect.Method.invokeNative (Native Method) At Java.lang.reflect.Method.invoke (method.java:525) at Com.android.internal.os.zygoteinit$methodandargscaller.run (zygoteinit.java:1209) at Com.android.internal.os.ZygoteInit.main (zygoteinit.java:1025) at Dalvik.system.NativeStart.main (Native Method)
The cause of the above exception, where did Layoutparams come from?
There are two ways to load a view: One is code AddView one is inflate.
1. Inflate method to load and add Layoutparams
Analysis of measure process, wrap_content and XML layout file parsing process in Android (Part I)
2. The following demo AddView way to add layoutparams
public class Mainactivity extends Activity { @Overrideprotected void onCreate (Bundle savedinstancestate) { Super.oncreate (savedinstancestate); Setcontentview (R.layout.activity_main); Customviewgroup Customviewgroup = (customviewgroup) Findviewbyid (R.id.custom_view_group); CustomViewGroup.addView ( Createtextview ("Love_world_"));} Private View Createtextview (String value) { TextView TextView = new TextView (this); Textview.settext ("A Child View"); Textview.settext (value); Textview.setlayoutparams (New Viewgroup.marginlayoutparams (Layoutparams.wrap_content, LayoutParams.WRAP_CONTENT)) ; return textView;} }
2. Viewgroup.addview source, find out where to add layoutparams
Public abstract class ViewGroup extends view implements Viewparent, Viewmanager {public void AddView (View child) { AddView (Child,-1); } public void AddView (view child, int index) {layoutparams params = Child.getlayoutparams ();//Sub-view Layoutparams NULL is the processing mode if (params = = null) {params = Generatedefaultlayoutparams (); if (params = = null) {throw new IllegalArgumentException ("Generatedefaultlayoutparams () cannot return null" ); }} addview (Child, index, params); } public void AddView (View child, int width, int height) {final Layoutparams params = Generatedefaultlayoutpara MS (); Params.width = width; Params.height = height; AddView (Child,-1, params); } public void AddView (View child, Layoutparams params) {AddView (Child,-1, params); } public void AddView (View child, int index, layoutparams params) {if (DBG) {System.out.println(This + "AddView"); }//Addviewinner () would call Child.requestlayout () when setting the new Layoutparams//Therefore, we call Requestlayout () on ourselves before, so then the child's request//would be a blocked at our level Requestlayo UT (); Invalidate (); Addviewinner (Child, index, params, false); }//Child View Default Layoutparams instance protected Layoutparams Generatedefaultlayoutparams () {return new Layoutparams (Layoutparams. Wrap_content, layoutparams.wrap_content); }//definition Layoutparams class public static class Layoutparams {public int width;public int height;public layoutparams (int width, int Height) {this.width = width; This.height = height; }}}
Here are the key
Public abstract class ViewGroup extends view implements Viewparent, Viewmanager { private void Addviewinner (View child , int index, layoutparams params, boolean preventrequestlayout) { if (child.getparent () = null) { throw new I Llegalstateexception ("The specified child already have a parent." + "You must call Removeview () on the child ' s parent First. "); } if (!checklayoutparams (params)) { params = generatelayoutparams (params); } if (preventrequestlayout) { child.mlayoutparams = params; } else { child.setlayoutparams (params); } ...... } Protected Boolean checklayoutparams (Viewgroup.layoutparams p) { return P! = null; }}
By looking at the AddView add layoutparams code above, you can discover solutions that replicate these functions, creating layoutparams from the current custom view to inherit from Marginlayoutparams.
public class Customviewgroup extends ViewGroup {@Override protected void onmeasure (int widthmeasurespec, int heightmeas Urespec) {...} @Override protected void OnLayout (Boolean changed, int left, int top, int. right, int bottom) {...} @Override protected Layoutparams generatelayoutparams (Viewgroup.layoutparams p) {return new Layoutparams (p); } @Override protected Layoutparams generatedefaultlayoutparams () {return new Layoutparams (layoutparams . Match_parent, layoutparams.wrap_content); } @Override Public Layoutparams generatelayoutparams (AttributeSet attrs) {return new Layoutparams (GE Tcontext (), attrs); }//Inherit from margin, support child View Android:layout_margin property public static class Layoutparams extends Marginlayoutparams { Public Layoutparams (Context C, AttributeSet attrs) {super (C, attrs); } public layoutparams (int width, int height) {Super (width, height); } publiC Layoutparams (Viewgroup.layoutparams source) {super (source); } public Layoutparams (Viewgroup.marginlayoutparams source) {super (source); } }}
Android View measure (v) supports the margin attribute, starting with an exception