Android Custom View Constructor detailed _android

Source: Internet
Author: User

Constructor for initial custom view

I've written a blog that implements a circular progress bar (a custom circular progress bar), and usually when we implement custom view, we inherit the view and implement the three constructors of view, such as:

Import Android.content.Context;
Import Android.graphics.Canvas;
Import Android.util.AttributeSet;
Import Android.view.View;

public class Mycustomview extends View {
 /**
  * First constructor/public
 Mycustomview (context context) {
  This (context, null);
 }

 /**
  * Second constructor/public
 Mycustomview (context, AttributeSet attrs) {This (context
  , attrs, 0 );
 }

 /**
  * The third constructor/
  public
 mycustomview (context, AttributeSet attrs, int defstyle) {
  super ( Context, attrs, defstyle);
  TODO: Get custom attribute
 }

 @Override
 protected void OnDraw (Canvas Canvas) {
  super.ondraw (Canvas);
 }
}

There are many statements about the timing of the use of three of constructors on the web, but there are few that are true, and here is a formal popular science:

The first constructor is called when you directly new a custom view instance in your code. There is no dispute about this.
When you invoke custom view in an XML layout file, the second constructor is called. This is not disputed.
When you invoke custom view in an XML layout file, and the Custom View tab has a customized property, the second constructor is called here.
That is, the system defaults to only the first two constructors of custom view, and the invocation of the third constructor, which is typically called by ourselves in the constructor (for example, invoking the third constructor in the second constructor).

The acquisition of custom attributes is usually done through the Obtainstyledattributes function in the constructor. Here's how to generate custom properties for custom view.

Generate custom properties for custom view

Custom View adding custom properties is primarily a custom attribute that is configured with the declare-styleable tag by adding a resources XML file under the Res/values/directory, as shown in the following example (res/values/ Attrs_my_custom_view.xml):

<resources>
 <declare-styleable name= "Mycustomview" >
  <attr name= "CUSTOM_ATTR1" String "/>
  <attr name=" custom_attr2 "format=" string "/>
  <attr name=" Custom_attr3 "format=" string "/>
  <attr name=" CUSTOM_ATTR4 "format=" string "/>
 </declare-styleable>
 <attr name=" CUSTOM_ATTR5 "format=" string "/>
</resources>

In the XML file above, we declare a custom attribute set Mycustomview, which contains the CUSTOM_ATTR1,CUSTOM_ATT2,CUSTOM_ATTR3,CUSTOM_ATTR4 four properties. At the same time, We also declare a separate attribute CUSTOM_ATTR5.

Properties declared in all resources files generate corresponding member variables in the R.attr class:

Public final class R {public
 static final class attr {public
  static final int custom_attr1=0x7f010038;
  public static final int custom_attr2=0x7f010039;
  public static final int custom_attr3=0x7f01003a;
  public static final int custom_attr4=0x7f01003b;
  public static final int custom_attr5=0x7f010000;
 }
}

However, the attributes declared in the label will also generate the associated member variables in the R.styleable class:

public static final class Styleable {public
  static final int[] Mycustomview = {
   0x7f010038, 0x7f010039, 0x7f010 03a, 0x7f01003b
  };
  public static final int mycustomview_custom_attr1 = 0;
  public static final int mycustomview_custom_attr2 = 1;
  public static final int mycustomview_custom_attr3 = 2;
  public static final int mycustomview_custom_attr4 = 3;
}

As you can see, R.styleable.mycustomview is an array in which the element value happens to be the R.ATTR.CUSTOM_ATTR1~R.ATTR.CUSTOM_ATTR4 value. and the following Mycustomview_custom _ATTR1~MYCUSTOMVIEW_CUSTOM_ATTR4 is exactly the index of its counterpart.

With that in view, we can learn how to get the value of a custom property in the constructor of custom see.

Get custom properties in the constructor of custom view

The code to get the custom property in the third constructor is as follows:

Public Mycustomview (context, AttributeSet attrs, int defstyleattr) {
 Super (context, attrs, defstyleattr); C2/>typedarray ta = context.obtainstyledattributes (attrs, r.styleable.mycustomview);

 String attr1 = ta.getstring (R.STYLEABLE.MYCUSTOMVIEW_CUSTOM_ATTR1);
 String attr2 = ta.getstring (R.STYLEABLE.MYCUSTOMVIEW_CUSTOM_ATTR2);
 String ATTR3 = ta.getstring (R.STYLEABLE.MYCUSTOMVIEW_CUSTOM_ATTR3);
 String ATTR4 = ta.getstring (R.STYLEABLE.MYCUSTOMVIEW_CUSTOM_ATTR4);

 LOG.E ("CustomView", "attr1=" + attr1);
 LOG.E ("CustomView", "attr2=" + attr2);
 LOG.E ("CustomView", "attr3=" + attr3);
 LOG.E ("CustomView", "attr4=" + ATTR4);
 Ta.recycle ();
 }

On the acquisition of custom attributes, we mainly call the Context.obtainstyledattributes function, we believe that the function of the custom view is very skilled. Let's take a look at the source code implementation of this function:

Public final TypedArray obtainstyledattributes (AttributeSet set, @StyleableRes int[] attrs) {return
 gettheme (). Obtainstyledattributes (set, attrs, 0, 0);
}

By tracing the source code, we found that the Obtainstyledattributes method of the two parameters of the context was ultimately called the Obtainstyledattributes method of theme 4 parameters. Let's take a look at the source code implementation for this function:

Public TypedArray obtainstyledattributes (AttributeSet set, @StyleableRes int[] attrs, @AttrRes int defstyleattr, @Style
 Res int defstyleres) {final int len = attrs.length;

 Final TypedArray array = Typedarray.obtain (Resources.this, Len);
 XXX Note this is for now and only work with compiled XML files. To support generic XML files We'll need to manually parse/out of the attributes from the XML file (applying type inf
 Ormation//contained in the and such).
 Final Xmlblock.parser Parser = (xmlblock.parser) set;  Assetmanager.applystyle (Mtheme, defstyleattr, defstyleres, parser!= null? parser.mparsestate:0, Attrs, Array.mData,

 Array.mindices);
 Array.mtheme = this;

 Array.mxml = parser;

  if (false) {int[] data = Array.mdata;
  System.out.println ("Attributes:");
  String s = "attrs:";
  int i;
   for (i=0; I<set.getattributecount (); i++) {s = s + "" + set.getattributename (i);
   int id = set.getattributenameresource (i); if (ID!= 0) {s = s + "(0x" + integer.tohexstring (ID) + ")";
  } s = s + "=" + Set.getattributevalue (i);
  } System.out.println (s);
  s = "Found:";
  Typedvalue value = new Typedvalue ();
   For (i=0 i<attrs.length; i++) {int d = i*assetmanager.style_num_entries;
   Value.Type = Data[d+assetmanager.style_type];
   Value.data = Data[d+assetmanager.style_data];
   Value.assetcookie = Data[d+assetmanager.style_asset_cookie];
   Value.resourceid = data[d+assetmanager.style_resource_id];
  s = s + "0x" + integer.tohexstring (Attrs[i]) + "=" + value;
 } System.out.println (s);
} return array;

 }

Here does not do too much source code explanation, but the meaning of these four parameters to explain to everyone:

AttributeSet set: A collection of property values.

int[] Attrs: Our custom attribute collection is an int array generated in the R class. This array contains the resource IDs of the custom attributes.
int defstyleattr: This is a reference to the style contained in the current theme. When we do not set the Declare-styleable resource collection for custom view, The default is to find the configuration attribute values in the layout file from this collection. Incoming 0 means that the default value is not found in the defstyleattr.
int Defstyleres: This is also a resource ID pointing to style, but it works only if defstyleattr is 0 or defstyleattr is not 0 but theme does not assign a value to the Defstyleattr property.

Because a property can be assigned to it in many places, including: XML layout files, decalare-styleable, theme medium, they are prioritized, sorted by priority from high to low as follows:

Attribute Assignment Precedence Order table:

Define directly in Layout XML > in layout XML by specifying a style reference in the theme of a style definition > the activity of the custom view Defstyleres the default value specified in the

To give you a clearer and more intuitive understanding, and then to set up the chapter on custom properties, I'll define the 4 attributes of custom_attr1~4 in each of these four places, and then get the value in the constructor of custom view to see Whether the order of precedence is the same as we expected.

Set custom property values

The following parameters are described in the Obtainstyledattributes four parameter construction method for the Resources.theme class.

second argument --assigning values to attributes in a layout XML file

Before setting a custom attribute, we first call our custom View in the layout file of the main activity and set a specific property for it.

The main layout file contents are as follows:

<framelayout xmlns:android= "http://schemas.android.com/apk/res/android"
 xmlns:custom= "http:// Schemas.android.com/apk/res-auto "
 android:id=" @+id/container "
 android:layout_width=" Match_parent
 " android:layout_height= "Match_parent" >

 <com.kevintan.eventbussample.view.mycustomview
  android:id= "@+id/id_custom_view"
  android:layout_width= "400DP"
  android:layout_height= "400DP"
  custom:custom_ attr1= "Attr1_xml"
  style= "@style/testcustomview"/>

</FrameLayout>

Sample results:

05-28 17:19:56.542 23575-23575/? E/customview:attr1=attr1_xml
05-28 17:19:56.542 23575-23575/? E/customview:attr2=null
05-28 17:19:56.542 23575-23575/? E/customview:attr3=null
05-28 17:19:56.542 23575-23575/? E/customview:attr4=null

Attention:

When assigning a custom attribute, you first need to increase the namespace of the custom attribute, for example: xmlns:custom= "Http://schemas." Android.com/apk/res-auto ", Android Studio recommends using Res-auto, and in eclipse you need to use the package name of the Custom view: xmlns:cv=" http:// Schemas.android.com/apk/com.kevintan.eventbussample.view "
Here, in the layout file, we assign CUSTOM_ATTR1 to: Attr1_xml. Getting this property value in Custom view corresponds to Gettheme (). The second parameter in the Obtainstyledattributes method @styleableres Int[] Attrs

second argument --Assigning a property in style

Second, custom attributes can also be assigned in style.

First, we add a custom Style,style code to Mycustomview in the XML layout file as follows:

<style name= "Testcustomview" >
 <item name= "custom_attr1" >attr1_style</item>
 <item Name= "CUSTOM_ATTR2" >attr2_style</item>
</style>

We then modify the layout file to add the style field:

<framelayout xmlns:android= "http://schemas.android.com/apk/res/android"
 xmlns:custom= "http:// Schemas.android.com/apk/res-auto "
 android:id=" @+id/container "
 android:layout_width=" Match_parent
 " android:layout_height= "Match_parent" >

 <com.kevintan.eventbussample.view.mycustomview
  android: Id= "@+id/id_custom_view"
  android:layout_width= "400DP"
  android:layout_height= "400DP"
  Custom: custom_attr1= "Attr1_xml"
  style= "@style/testcustomview"/>

</FrameLayout>

Sample results:

05-28 17:19:56.542 23575-23575/? E/customview:attr1=attr1_xml
05-28 17:19:56.542 23575-23575/? E/customview:attr2=attr2_style
05-28 17:19:56.542 23575-23575/? E/customview:attr3=null
05-28 17:19:56.542 23575-23575/? E/customview:attr4=null

Here we assign the CUSTOM_ATTR1 attribute again, and we also assign the CUSTOM_ATTR2 to the value.

Small tip:

Smart classmates must have guessed the effect of this assignment, but I would like to briefly:
For CUSTOM_ATTR1, we assign values in XML layout files, style, Defstyle, and theme, and the resulting results will inevitably confirm who has the highest priority.
For CUSTOM_ATTR2, we assign values in style, Defstyle, and theme, and by the results we know who has the second highest priority.
For CUSTOM_ATTR3 and CUSTOM_ATTR4 of the assignment, I do not explain, I believe we all understand!!
At the same time, it is also necessary to note that as long as it is in the layout layout file, either through the namespace directly to the property assignment, or through the style for the property assignment, in the constructor to obtain the corresponding Gettheme (). The second parameter in the Obtainstyledattributes method @styleableres int[] Attrs

Third parameter defstyleattr

The meaning of this parameter is:

Original: An attribute in the "current theme" contains areference to a style resource which supplies values for the T Ypedarray. Can is 0 to don't look for defaults.
Translation: This is a reference to style that is contained in the current theme. When we do not set the Declare-styleable resource collection for custom view, The default is to find the configuration attribute values in the layout file from this collection. Incoming 0 means that the default value is not found in the defstyleattr.
To test the role and priority of this parameter, we need to do the following.

First, we declare a property of the refrence format used to represent the reference to the style. The declaration is in the previous Res/values/attrs_my_custom_view.xml file:

<attr name= "mycustomviewdefstyleattr" format= "Reference"/>

Then, you need to go to androidmanifest.xml to see the topics that are used by the activity that contains the custom view:

<activity>
 android:name= "com.kevintan.eventbussample.MainActivity"
 android:theme= "@style Apptheme "
 android:label=" @string/app_name ">
 <intent-filter>
  <action android:name=" Android.intent.action.MAIN "/>
  <category android:name= android.intent.category.LAUNCHER"/>
 < /intent-filter>
</activity>

Finally, add the MYCUSTOMVIEWDEFSTYLEATTR reference implementation under the Apptheme theme in Style.xml.

<style name= "Apptheme" parent= "Android:Theme.Holo.Light.DarkActionBar" >
 <!--Customize your here. -->
 <item name= "mycustomviewdefstyleattr" > @style/mycustomviewdefstyleattrimpl</item>
</style>

<style name= "Mycustomviewdefstyleattrimpl" >
 <item name= "CUSTOM_ATTR1" >attr1_ defstyleattr</item>
 <item name= "custom_attr2" >attr2_defStyleAttr</item>
 <item name= "Custom_attr3" >attr3_defStyleAttr</item>
</style>

Code validation, remember that if you want to use the third parameter of the Obtainstyledattributes method, you need the Obtainstyledattributes method of the call Gettheme () that is displayed in the third constructor.

The public Mycustomview (context, AttributeSet attrs) {
 //is assigned to Defstyleattr
 (context, Attrs, r.attr.mycustomviewdefstyleattr);
}

Public Mycustomview (context, AttributeSet attrs, int defstyleattr) {
 Super (context, attrs, defstyleattr); C6/>typedarray ta = Context.gettheme (). Obtainstyledattributes (Attrs, R.styleable.mycustomview, defStyleAttr, 0);

 String attr1 = ta.getstring (R.STYLEABLE.MYCUSTOMVIEW_CUSTOM_ATTR1);
 String attr2 = ta.getstring (R.STYLEABLE.MYCUSTOMVIEW_CUSTOM_ATTR2);
 String ATTR3 = ta.getstring (R.STYLEABLE.MYCUSTOMVIEW_CUSTOM_ATTR3);
 String ATTR4 = ta.getstring (R.STYLEABLE.MYCUSTOMVIEW_CUSTOM_ATTR4);

 LOG.E ("CustomView", "attr1=" + attr1);
 LOG.E ("CustomView", "attr2=" + attr2);
 LOG.E ("CustomView", "attr3=" + attr3);
 LOG.E ("CustomView", "attr4=" + ATTR4);
 Ta.recycle ();
}

In the code, there are two points to be noted:

I have already assigned the defstyleattr in the second constructor parameter, and the third constructor directly uses the incoming parameter.
In the third construct parameter, I use the Gettheme () Obtainstyledattributes method to replace the Obtainstyledattributes construction method of the 2 parameters of the context.
Sample results:

05-28 17:19:56.542 23575-23575/? E/customview:attr1=attr1_xml
05-28 17:19:56.542 23575-23575/? E/customview:attr2=attr2_style
05-28 17:19:56.542 23575-23575/? E/customview:attr3=attr3_defstyleattr
05-28 17:19:56.542 23575-23575/? E/customview:attr4=null

As you can see from the results, the precedence of the style reference specified in the topic is lower than the direct assignment in XML and the use of the style field.

At the same time, we also need to know a little:
Many of the controls in the Android system use a third parameter, such as a button, in the constructor parameters. The advantage of this is that when we switch between different themes, the button style changes as well.

Fourth Argument --Assigning a property by Defstyleres

The meaning of this parameter is:

Original: A resource identifier of a style resource that supplies default values for the TypedArray, used only if defstyleattr I s 0 or can found in the theme. Can is 0 to don't look for defaults.
Translation: This is a resource ID pointing to style, but it works only if the defstyleattr is 0 or defstyleattr is not 0 but theme does not assign a value to the Defstyleattr property.
By translating, we can make clear two points:

1.defStyleRes: Point to a style reference.
2.defStyleRes has a lower priority than defstyleattr.
To verify, we first define a style in the Theme.xml file:

<style name= "Mycustomviewdefstyleres" >
 <item name= "CUSTOM_ATTR1" >attr1_defStyleRes</item>
 <item name= "custom_attr2" >attr2_defStyleRes</item>
 <item name= "CUSTOM_ATTR3" >attr3_ defstyleres</item>
 <item name= "CUSTOM_ATTR4" >attr4_defStyleRes</item>
</style>

We then assign values in the Obtainstyledattributes function in the third constructor of the custom view, as follows:

Public Mycustomview (context, AttributeSet attrs) {This
 (context, attrs, r.attr.mycustomviewdefstyleattr);
}

Public Mycustomview (context, AttributeSet attrs, int defstyleattr) {
 Super (context, attrs, defstyleattr); c5/>//is assigned to defstyleres
 TypedArray ta = Context.gettheme (). Obtainstyledattributes (Attrs, R.styleable.mycustomview, Defstyleattr, r.style.mycustomviewdefstyleres);

 String attr1 = ta.getstring (R.STYLEABLE.MYCUSTOMVIEW_CUSTOM_ATTR1);
 String attr2 = ta.getstring (R.STYLEABLE.MYCUSTOMVIEW_CUSTOM_ATTR2);
 String ATTR3 = ta.getstring (R.STYLEABLE.MYCUSTOMVIEW_CUSTOM_ATTR3);
 String ATTR4 = ta.getstring (R.STYLEABLE.MYCUSTOMVIEW_CUSTOM_ATTR4);

 LOG.E ("CustomView", "attr1=" + attr1);
 LOG.E ("CustomView", "attr2=" + attr2);
 LOG.E ("CustomView", "attr3=" + attr3);
 LOG.E ("CustomView", "attr4=" + ATTR4);
 Ta.recycle ();
}

Test results:

05-28 17:44:09.282 3137-3137/? E/customview:attr1=attr1_xml
05-28 17:44:09.282 3137-3137/? E/customview:attr2=attr2_style
05-28 17:44:09.282 3137-3137/? E/customview:attr3=attr3_defstyleattr
05-28 17:44:09.282 3137-3137/? E/customview:attr4=null

Focus:
If we seriously look at the results of the experiment, will certainly be surprised by the results above, clearly specified the Defstyleres, why ATTR4 value or null?
It's because we've talked about the use priority of Defstyleres: it only works if Defstyleattr is 0 or if the Defstyleattr attribute is not assigned to the current theme.

So, here we need to modify the constructor to set the defstyleattr to 0.

Public Mycustomview (context context, AttributeSet attrs) {
 //To verify the role of Defstyleres, set the defstyleattr to 0 this
 ( Context, attrs, 0);
}

Public Mycustomview (context, AttributeSet attrs, int defstyleattr) {
 Super (context, attrs, defstyleattr); C6/>typedarray ta = Context.gettheme (). Obtainstyledattributes (Attrs, R.styleable.mycustomview, DefStyleAttr, R.style.mycustomviewdefstyleres);

 String attr1 = ta.getstring (R.STYLEABLE.MYCUSTOMVIEW_CUSTOM_ATTR1);
 String attr2 = ta.getstring (R.STYLEABLE.MYCUSTOMVIEW_CUSTOM_ATTR2);
 String ATTR3 = ta.getstring (R.STYLEABLE.MYCUSTOMVIEW_CUSTOM_ATTR3);
 String ATTR4 = ta.getstring (R.STYLEABLE.MYCUSTOMVIEW_CUSTOM_ATTR4);

 LOG.E ("CustomView", "attr1=" + attr1);
 LOG.E ("CustomView", "attr2=" + attr2);
 LOG.E ("CustomView", "attr3=" + attr3);
 LOG.E ("CustomView", "attr4=" + ATTR4);
 Ta.recycle ();
}

Final Result:

05-28 17:49:03.707 5772-5772/? E/customview:attr1=attr1_xml
05-28 17:49:03.707 5772-5772/? E/customview:attr2=attr2_style
05-28 17:49:03.707 5772-5772/? E/customview:attr3=attr3_defstyleres
05-28 17:49:03.707 5772-5772/? E/customview:attr4=attr4_defstyleres

Postscript

At the end of the article, let's summarize the attribute assignment precedence for the custom attribute:

Define directly in the layout XML > specify the default value specified in Defstyleres in the theme in layout XML through the style definition > The activity of the custom view.

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.