Thursday, May 3, 2012

Android - Creating a Tabhost with ListView and Button under ListView

I decided this was worthy of a post since I had a hard time figuring this out. Android has a cool TabActivity which allow us to add tabs to our application. Of course we have to declare an XML file for our main window which includes all the containers and widgets needed to create UI:

Main.xml

<?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/tabhost"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical"
        android:padding="5dp" >

        <TabWidget
            android:id="@android:id/tabs"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" />

        <FrameLayout
            android:id="@android:id/tabcontent"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="4"
            android:padding="5dp" >

            <com.daish.viewtest.TestListView
                android:id="@+id/custom_list"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content" />
        </FrameLayout>

        <FrameLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="0"
            android:padding="5dp" >

            <Button
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:text="BUTTON UNDER LISTVIEW!" />
        </FrameLayout>
    </LinearLayout>

</TabHost>

The XML layout includes a tabwidget, listview, and a button. The trick here is android:layout_weight="" which indicates which widget will take up portions of the screen. I also added a button which took up another portion. When it comes down to FrameLayouts, you have to indicate the weight to determine how much of the screen it will take up or else some widgets will appear to float infront of another, which is the nature of a framelayout. The problem is Tabhost needs to have a Framelayout for its content of the tabs and this was a way I found to add button. Linear Layout and Relative layout did not work for me. If someone has a better way, please feel free to share.

Here is my Main Activity Class:

import android.app.TabActivity;
import android.os.Bundle;
import android.widget.TabHost;

public class ViewTestActivity extends TabActivity
{
 /** Called when the activity is first created. */
 @Override
 public void onCreate(Bundle savedInstanceState)
 {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);

  TabHost tabHost = getTabHost(); // The activity TabHost
  TabHost.TabSpec spec; // Resusable TabSpec for each tab

  //tab creation
  spec = tabHost.newTabSpec("Tab 1 Tag").setIndicator("Tab 1").setContent(R.id.custom_list);
  tabHost.addTab(spec);

  spec = tabHost.newTabSpec("Tab 2 Tag").setIndicator("Tab 2").setContent(R.id.custom_list);
  tabHost.addTab(spec);

  tabHost.setCurrentTab(1);

 }
}

Here is the Class which extends ListView:

import android.app.AlertDialog;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class TestListView extends ListView
{
 private ArrayAdapter<String> test;
 String[] testItems = {"Larry", "John", "Gary","Larry", "John", "Gary","Larry", "John", "Gary","Larry", "John", "Gary","Larry", "John", "Gary","Larry", "John", "Gary"};
 
 //If built programmatically
 public TestListView(Context context)
 {
  super(context);
  init();
 }
 //This example uses this method since being built from XML
 public TestListView(Context context, AttributeSet attrs)
 {
  super(context, attrs);
  init();
 }
 
 //Build from XML layout 
 public TestListView(Context context, AttributeSet attrs, int defStyle)
 {
  super(context, attrs, defStyle);
  init();
 }
 
 public void init()
 {
  test = new ArrayAdapter<String>(getContext(),R.layout.row, R.id.label , testItems);
  setAdapter(test);
  setOnItemClickListener(new ListSelection());
 }
 
 private class ListSelection implements OnItemClickListener
 {

  @Override
  public void onItemClick(AdapterView<?> parent, View view, int position,
    long id)
  {
   AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
   builder.setMessage("You pressed item #" + (position+1));
   builder.setPositiveButton("OK", null);
   builder.show();
  }
  
 }
}

Here is the result of code above. Enjoy!