Wednesday, December 3, 2014

Using Android's LayoutInflater

In my last few articles on Android, I showed you how to build a list view. Before we move on with custom list views, I want to analyse the below inflate API as we will be using it to inflate the list item and add it to the ListView parent.

View inflate(int resource, ViewGroup root, boolean attachToRoot)
  • inflate API inflates an XML layout into a view. 
  • resource is the XML layout resource to be inflated
  • root will be its parent layout if attachToRoot is true. The view will be automatically added as child to parent. The attributes of child XML layout if any will be ignored.
  • if attachToRoot is false, the child view won't be attached to the root and the root is only used to create the correct sub-class of the layout parms.
For example, if the parent is LinearLayout, the layout parms Object will be of class android.widget.LinearLayout$LayoutParms.If the parent is a ListView, layout parms will be of type android.widget.AbsListView$LayouParams

My parent layout is a simple LinearLayout.
parent_layout.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:id="@+id/text_container" >
<!-- child view will go here -->
</LinearLayout>


My child view is a simple text field
child_text_view.xml

<textview android:background="#ff0000" android:layout_height="200dp" android:layout_width="50dp" android:text="TEST LAYOUT" xmlns:android="http://schemas.android.com/apk/res/android">

</textview>


In the activity class, we will do the following:

  • First set the parent layout (LinerarLayout in our case) as the content view.
  • Next inflate the text view. 
Note in our first case, we pass null as root.

Activity class:

package com.jopc.sandbox;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;

public class LayoutInflateTestActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);

      //set the parent layout
      setContentView(R.layout.parent_layout);
      
      ViewGroup parent = (ViewGroup) findViewById(R.id.text_container);
      View textView = getLayoutInflater().inflate(R.layout.child_text_view, null);      
      parent.addView(textView);      
    }
}

Without any known parent, all LayoutParams you declared on the root element of your XML tree will not be read as there is no parent and hence will generate a default set of attributes.
As you can see, the width and height are not as expected. It simply ignored the values set in the XML.









Eclipse warning bulb hints us to avoid passing null as root as it will be used to resolve layout parameters on the inflated layout's root element.



I will fix the issue and rerun the example.

In the below activity class, I am now passing the parent layout as root.

package com.jopc.sandbox;

import android.app.Activity;
import android.os.Bundle;
import android.view.ViewGroup;

public class LayoutInflateTestActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);

      //set the parent layout
      setContentView(R.layout.parent_layout);
      
      ViewGroup parent = (ViewGroup) findViewById(R.id.text_container);
      getLayoutInflater().inflate(R.layout.child_text_view, parent, true);          
    }
}

When I re-run the app, I can see the child view has now retained its layout parms from the XML.



Conclusion is we should always try to pass the parent layout. In my next article, I will show you how to build our own custom view.


No comments:

Post a Comment