Custom control states in library projects


SDK Version: 
M3

This is a tutorial about adding states to custom controls in library projects. So first, how to create and reference library projects: Setting up library projects, Referencing library projects.

Now that the project is setup you can start creating custom controls and states for them. This will all be inside the library project. Firstly you need to create an attributes xml file in values/attrs.xml (the name has to be attrs.xml) and adding the state:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <resources>    
  3.     <declare-styleable name="customTextViewState";>
  4.         <attr name="state_marked" format="boolean" />
  5.     </declare-styleable>    
  6. </resources>

Next is adding the state to the custom control (in this case a textview). Simply create a new class that extends TextView and add these two private variables:

  1. private static final int[] STATE_MARKED = {R.attr.state_marked};
  2. private boolean isMarked;

Secondly create a setter method for isMarked:

  1. public void setMarked(boolean isMarked)
  2. {
  3.     this.isMarked = isMarked;
  4.     refreshDrawableState();
  5. }

Calling refreshDrawableState() is necessary for the textview to update its drawable state.

And finally overriding onCreateDrawableState method:

  1. @Override
  2. protected int[] onCreateDrawableState(int extraSpace)
  3. {
  4.      final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
  5.      if (isMarked)
  6.      {
  7.          mergeDrawableStates(drawableState, STATE_MARKED);
  8.      }
  9.     return drawableState;
  10. }

After this you're finished with the library, next step is to create a project and reference the library. Then add the previously created custom control to your layout:

  1. <com.helloandroid.lib.CustomTextView
  2.     android:layout_width="wrap_content"
  3.     android:layout_height="wrap_content"
  4.     android:text="Random text"
  5.     android:textColor="@drawable/textview_color_selector">
  6. </com.helloandroid.lib.CustomTextView>

The name should be library package name + the custom control class name inside that package. In this case there's a package inside the library project called com.helloandroid.lib and inside that there's the custom textview called CustomTextView.

And finally the very last step is to create the textview_color_selector xml file. To do so create a file in one of the drawable folders called textview_color_selector.xml:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <selector xmlns:android="http://schemas.android.com/apk/res/android"
  3.         xmlns:app="http://schemas.android.com/apk/res/com.helloandroid.myapp" >
  4.    
  5.     <item app:state_marked="true" android:color="#347829"/>
  6.     <item android:color="#FFFFFF"/>
  7. </selector>

Notice the app xml namespace, the package name is not the library package name. Because of a bug/limitation in android you have to write the package name of the project you're using the library in. For example if you have a library package com.helloandroid.lib and a project that references this library with a package name of com.helloandroid.useslib then you have to write this xml namespace import:

  1. xmlns:app="http://schemas.android.com/apk/res/com.helloandroid.useslib"

and not
  1. xmlns:app="http://schemas.android.com/apk/res/com.helloandroid.lib"

even though the state is declared inside the library project. Hopefully this will get fixed someday. After all this you can use the CustomTextView's setMarked(boolean) method to change the state and the text color will be updated.