Using Fragment attributes (in the XML layout files)

I had to dig for a while (some 10 minutes) to get my android fragments to receive the attributes form the xml layout.

This is how I got it working.

Starting by with a fragment (I'm using Jake Burton's ActionBarSherlok but the same should work when extending the support or original fragment classes):

    1: class MyOwnFragment extends extends SherlockFragment {
    2:         /* fragments attributes */
    3:         private int    padding = 8; // default value that will be overridden if there's a layout attributes
    4:         private String lavel   = ""; // default value that will be overridden if there's a layout attributes
    5: 
    6:         @Override
    7:         public void onCreate (Bundle savedInstanceState) {
    8:                 super.onCreate (savedInstanceState);
    9:                 if (savedInstanceState != null) {
   10:                         // use the saved state that was set in the #onSaveInstanceState
   11:                 }
   12:         }
   13: 
   14:         @Override
   15:         public void onSaveInstanceState (Bundle outState) {
   16:                 // save the state of our fragment into the outState bundle.
   17:         }
   18: 
   19: 
   20:         @Override
   21:         public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
   22:                 View fragmentRootView = // what ever you need, inflate a layout, progamatically create a view, etc.
   23: 
   24:                 // if there were attibutes in the layout XML
   25:                 // then we would have captured them in the #onInflate method
   26:                 // so we would already have them available
   27: 
   28:                 // we can also use the savedInstanceState here
   29:                 // to set child views of GroupView for example.
   30: 
   31:                 return fragmentRootView;
   32:         }
   33: 
   34:         @Override
   35:         public void onInflate (Activity activity, AttributeSet attrs, Bundle savedInstanceState) {
   36:                 super.onInflate (activity, attrs, savedInstanceState);
   37:                 TypedArray typedArray = activity.obtainStyledAttributes(attrs, R.styleable.MyOwnFragment);
   38:                 if (typedArray != null) {
   39:                         // this is where we can get out attributes.
   40:                         // we can "parse" them into class fields
   41:                         this.padding = typedArray.getDimensionPixelSize (R.styleable.MyOwnFragment_padding, this.padding);
   42:                         String labelAttr = typedArray.getString (R.styleable.MyOwnFragment_label);
   43:                         if (labelAttr != null) {
   44:                                 this.label = labelAttr;
   45:                         }
   46:                 } else {
   47:                         // no attributes are defined
   48:                 }
   49:         }
   50: }

The R.stylable.MyOwnFragment is a reference to the styleable defined at res/attrs.xml:

    1: <?xml version="1.0" encoding="utf-8"?>
    2: <resources>
    3:         <declare-styleable name="MyOwnFragment">
    4:                 <attr name="padding" format="dimension" />
    5:                 <attr name="label" format="string" />
    6:         </declare-styleable>
    7: </resources>

And finally in the layout file:

    1: <?xml version="1.0" encoding="utf-8"?>
    2: <RelativeLayout
    3:         xmlns:android="http://schemas.android.com/apk/res/android"
    4:         xmlns:app="http://schemas.android.com/apk/res/our.package.name"
    5:         android:layout_width="fill_parent"
    6:         android:layout_height="fill_parent">
    7: 
    8:         <fragment android:name="our.package.name.MyOwnFragment"
    9:                 android:id="@+id/myOwnFragment"
   10:                 android:layout_width="wrap_content"
   11:                 android:layout_height="wrap_content"
   12:                 app:padding="2dp"
   13:                 app:label="Fragment label" />
   14: </RelativeLayout>

Now the trick I had to find was that the we need to use the namespace of our application in the layout XML or it doesn't work (the attributes do not arrive at our fragment onInflate method). The strange thing is that the android lint will then complain that the defined namespace is not used but if we ignore the warning everything works fine. The Fragment documentation and the sdk example are not very helpful. They reuse the android namespace but that seems not to work (for me at least) as then it complains that the attribute is not recognized.