Android Custom Layouts (Part 2): Custom Attributes and LayoutParams

In my previous post, I had written a bit about creating custom Layouts for Android. However to make a truly reusable layout there are a few more things we’d probably need:

  1. Some unique properties that you may want to assign to it via XML (Like LinearLayout has an orientation property unique to it)
  2. Custom LayoutParams object that you can assign to the children of the Layout to assign them properties that the layout can inspect when its laying the children out.
  3. For bonus points, package this container in an external library project so you can reuse the class in a bunch of projects (this will also force you to write truly decoupled code)

Creating custom properties:

Since most often we use XML to define our layouts, it makes sense that we would like to assign configuration properties in the XML file as well. The way you do this is by creating a bunch of declare-styleable nodes in your /res/values/attr.xml file. For example:

<resources>
    <declare-styleablename="MyCustomLayout">
        <attrname="mynewproperty"format="string"/>
        <attr name="mynewproperty2" format="string"/>
    </declare-styleable>
</resources>

The name property of the declare-stylable node should reflect the class-name of your custom View/ViewGroup. The attr node inside references the actual property you are trying to create, You can create a bunch of these properties here. The format of the property can be of the following types:

  • reference
  • string
  • color
  • dimension
  • boolean
  • integer
  • float
  • fraction
  • enum
  • flag

Once you have created the declare-stylable, you have to ensure that those values are visible from the XML document. This is done by adding a new namespace to your application. For example

<com.arpitonline.flint.containers.MyCustomLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:arpitonline="http://schemas.android.com/apk/res/com.arpitonline.mycoolapp"
... >

The new namespace is just your application package appended to the end of “http://schemas.android.com/apk/res/&#8221;. Now any property specified there will be retrievable in the constructor of your custom Layout which you can retrieve like so:

public MyCustomLayout(Context context, AttributeSet attrs) {
     super(context, attrs);

     TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.MyCustomLayout);
     CharSequence o = arr.getString(R.styleable.MyCustomLayout_mynewproperty);

          // do something here with your custom property     

     arr.recycle();
}

Note that its good practice to have getters and setters for the property that you are assigning via XML so that the layout can be instantiated just as completely via code. The method described above can be used as is for custom Views as well. For a more detailed explanation see this link.

Creating Custom LayoutParams

As you create custom layouts, you may want to assign properties to the children that the layout may contain. For example, RelativeLayout has properties like layout_centerHorizontally etc that aren’t relevant for children of LinearLayout ViewGroups.

First, you need to create the attributes in the declare-stylable nodes just as mentioned in step 1 usually with the convention MyCustomLayout_LayoutParams. These will be read by your custom LayoutParams object and kept as properties.

The next step is to create a public inner class named (by convention) LayoutParams that extends ViewGroup.LayoutParams. Additionally in the main ViewGroup class, you have to override 3 methods:

  1. public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs)
  2. protected boolean checkLayoutParams(ViewGroup.LayoutParams p);
  3. protected ViewGroup.LayoutParams generateDefaultLayoutParams ()

The way this works is if there are custom layout attributes in the children, you get the attributes when the framework calls generateLayoutParams method and its up to you to generate the LayoutParams object based on the values coming in and return it.

Once that is done, there is a call made to checkLayoutParams which seems to give you one last chance to see if the object you created is something you still want to use to determine layout information. This can be done by looking at the class of the LayoutParams object for example. If you return false here, your generateDefaultLayoutParams method will get called which should return a default layout object that you can use anyway.

The layoutparams object will now be magically available during your onLayout pass and can be looked up by calling the view.getLayoutParams() method which you can then use to size and position that particular view.

External Library Projects

Its convenient to package all your custom code in an external Library Project that your app can reference. Doing so is easy, just create a new Android application and check the isLibrary checkbox in the wizard. Then add the library project to your project by right clicking on your application project and going to Preferences > Android screen and clicking the Add… button.

Note that for a long time it wasn’t possible to add custom attrs in Library Projects, this was fixed in SDK 11

The only gotcha here is that everything you have done in your library project may be in the namespace of your library project but when referencing it in your main application, they are referenced with the namespace of the main application project.

I have started a new project on Github where I’ll post some custom layouts/classes that may be helpful. Its pretty early right now but you can see the above code in action at least at the repository.

Android Custom Layouts (Part 2): Custom Attributes and LayoutParams

3 thoughts on “Android Custom Layouts (Part 2): Custom Attributes and LayoutParams

  1. Barrett Crews says:

    Hi, I was doing some research on Comcast and came upon your blog. I represent a wireless technology company called C-Wav, c-wav.com and we’re interested in partnering with a provider such as comcast. It seems to me that innovation labs might the place to introduce an emerging technology to your company. Please have a look at our website and if you could please let me know how I might best proceed. You can reach me by email, barrett.crews@c-wav.com. Best regards, Barrett Crews

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s