Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile / Xamarin

MonoAndroid: Using TabHost in your mobile applications

5.00/5 (7 votes)
21 Nov 2013CPOL6 min read 62.4K   1.9K  
TabHost control in MonoAndroid

Introduction

This is third article in series of MonoAndroid, the previous two articles are generic BaseAdapter and android Grid View. In this article I am going to demonstrate use of TabHost control, its different from TabLayout provided by android mobile OS.

TabHost provided flexibility of managing data in different views by providing tabbed interface. 

TabHost basically a container, where you need to put tab widget, which will host tabbed interface and FrameLayout, within which the different views are presented. Here have a look

Image 1

In this article we will create Indian FlimStar Biography app based on TabHost

Step By Step we move forward

`
  1. Create Android application by selecting New ->Solutions and provide its name “TabHostDemo


    Image 2
    Figure 1: Creating Android Project!

  2.  
  3. Once Project is created, Open Resource Folder->Layout and Add new file of type tabItemLayout.axml

     

    Image 3
    Figure 2: Selecting New File!  

    Image 4 

    Figure 3: Select Layout file 

  4. Add Following code in layout file
    XML
    <?xml version="1.0" encoding="utf-8"?>
    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
        android:minWidth="25px"
        android:minHeight="25px"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/scrollView1">
        <LinearLayout
            android:orientation="vertical"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:minWidth="25px"
            android:minHeight="25px">
            <LinearLayout
                android:orientation="horizontal"
                android:minWidth="25px"
                android:minHeight="25px"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:id="@+id/linearLayout1">
                <ImageView
                    android:src="@android:drawable/ic_menu_gallery"
                    android:layout_width="wrap_content"
                    android:layout_height="fill_parent"
                    android:id="@+id/ivFilmStar"
                    android:adjustViewBounds="true" />
                <LinearLayout
                    android:orientation="vertical"
                    android:minWidth="25px"
                    android:minHeight="25px"
                    android:layout_width="match_parent"
                    android:layout_height="fill_parent"
                    android:id="@+id/linearLayout2"
                    android:layout_marginLeft="7.3dp">
                    <TextView
                        android:text="Large Text"
                        android:textAppearance="?android:attr/textAppearanceLarge"
                        android:layout_width="fill_parent"
                        android:layout_height="wrap_content"
                        android:id="@+id/txtFilmStar" />
                </LinearLayout>
            </LinearLayout>
            <TextView
                android:text="Small Text"
                android:textAppearance="?android:attr/textAppearanceSmall"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:id="@+id/txtFilmStarBio1" />
            <TextView
                android:text="Small Text"
                android:textAppearance="?android:attr/textAppearanceSmall"
                android:layout_width="fill_parent"
                android:layout_height="match_parent"
                android:id="@+id/txtFilmStarBio2" />
        </LinearLayout>
    </ScrollView>
        Let me explain how exactly I created this layout file
    • Change base layout from LinearLayout to ScrollView, Since Biography may contain lot of text, so its better to use ScrollView. 
    • Add LinearLayout with “Vertical” orientation 
    • Then Add LinearLayout with "Horizontal" orientation and add Image view and TextView in it.
    • Add two TextView for FilmStar Biography
    • Rest I have done little tweaking  for formatting  ImageView And TextView

    See how it look like in XamarinTm Studio Designer, once all tweaking is done :-

    Image 5

    Figure 4: Designer view of GridView custom item 

       
  5. Now add Activity based on above layout file (flimStarUI.cs), and add following code in it :-
    protected override void OnCreate (Bundle bundle)
    {
        base.OnCreate (bundle);
        SetContentView (Resource.Layout.tabItemLayout);
        // Create your application here
    }
    

    Here we associated the flimStarUI with tabItemLayout.axml, using SetContentView and passing resource id of layout file.

  6. Now add class by name FlimStarInformationModal and inherit from abstract generic class Java.Lang.Object,  here is code for FlimStarInformationModal class. (Similar to Step2, instead of adding Layout file, add C# class file) 
    C#
    public class FlimStarInformationModal : Java.Lang.Object
    {
        public string FilmStarName {get;set;}
        public int FlimStarImageID {get;set;}
        public string FilmStarBio1 {get;set;}
        public string FilmStarBio2 {get;set;}
    }
    
    Each object of above class will act as content for TabLayout.


  7. Now in Main.axml layout file, code look like as follow:-
    XML
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
        <Button
            android:id="@+id/myButton"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="@string/hello" />
        <TabHost
            android:minWidth="25px"
            android:minHeight="25px"
            android:layout_width="fill_parent"
            android:layout_height="match_parent"
            android:id="@+id/tabHost1">
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical"
                android:id="@+id/linearLayout1">
                <TabWidget
                    android:id="@android:id/tabs"
                    android:layout_width="match_parent"
                    android:layout_height="69.3dp" />
                <FrameLayout
                    android:id="@android:id/tabcontent"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent" />
            </LinearLayout>
        </TabHost>
    </LinearLayout>               
    • Rename Button name to "Create TabHost Control", On button click we will create TabHost on runtime. 
    • Now, Add TabHost control on your layout file. 
    • By default, it would add TabWidget and Frame Layout under TabHost container.
    C#
    Dictionary<string,FlimStarInformationModal> dictFlimStarInfo = new Dictionary<string, FlimStarInformationModal>();
    
    protected override void OnCreate (Bundle bundle)
    {
    	base.OnCreate (bundle);
    	// Set our view from the "main" layout resource
    	SetContentView (Resource.Layout.Main);
    
    	Button button = FindViewById<Button> (Resource.Id.myButton);			
    
    	button.Click += delegate {
    		OnCreateTabHostControl(bundle);
    	};
    
    	CreateFlimStarInformationDict ();
    }
    
    void CreateFlimStarInformationDict()
    {
    	dictFlimStarInfo.Add ("Amitabh", new FlimStarInformationModal () {
    		FilmStarName = "Amitabh Bachan",
    		FlimStarImageID = Resource.Drawable.amitabh,
    		FilmStarBio1 = "Amitabh Harivansh Bachchan (born 11 October 1942) is an Indian film actor. He first gained popularity in the early 1970s as the \"angry young man\" of Hindi cinema, and has since appeared in over 180 Indian films in a career spanning more than four decades. Bachchan is widely regarded as one of the greatest and most influential actors in the history of Indian cinema.So total was his dominance of the movie scene in the 1970s and 1980s that the French director Francois Truffaut called him a \"one-man industry\".",
    		FilmStarBio2 = "shares with Kamal Hassan and Mammootty), a number of awards at international film festivals and award ceremonies and fourteen Filmfare Awards. He is the most-nominated performer in any major acting category at Filmfare, with 39 nominations overall. In addition to acting, Bachchan has worked as a playback singer, film producer and television presenter. He also had a stint in politics in the 1980s. The Government of India honoured him with the Padma Shri in 1984 and the Padma Bhushan in 2001 for his contributions towards the arts.",
    	});
    
    	dictFlimStarInfo.Add ("Shahrukh", new FlimStarInformationModal () {
    		FilmStarName = "Shahrukh Khan",
    		FlimStarImageID = Resource.Drawable.SRK,
    		FilmStarBio1 = "Shahrukh Khan (born 2 November 1965), often credited as Shah Rukh Khan and informally referred as SRK, is an Indian film actor. Referred to in the media as \"Badshah of Bollywood\", \"King Khan\" and \"King of Romance\", Khan has acted in 75 Hindi films in genres ranging from romantic dramas to action thrillers.[4][5][6][7] His contributions to the film industry have garnered him numerous achievements, including fourteen Filmfare Awards from thirty nominations. His eighth Filmfare Best Actor Award win made him the most awarded Bollywood actor of all time in that category, tied only with actor Dilip Kumar. In 2005, the Government of India honoured him with the Padma Shri for his contributions towards Indian cinema.",
    		FilmStarBio2 = "Khan is considered to be one of the biggest film stars in cinematic history, with a fan following claimed to number in the billions; in 2011, the Los Angeles Times called him \"the world's biggest movie star.\"[19] He has also been regularly featured in the listing of the most powerful names in Indian Cinema and in 2008, Newsweek named him one of the 50 most powerful people in the world.[5] Khan has an estimated net worth of over US $600 million(INR25 billion).",
    	});
    
    	dictFlimStarInfo.Add ("Hrithik", new FlimStarInformationModal () {
    		FilmStarName = "Hrithik Roshan",
    		FlimStarImageID = Resource.Drawable.Hrithik,
    		FilmStarBio1 = "Hrithik Roshan (born on 10 January 1974) is an Indian film actor and professional dancer.[1][2] Having appeared as a child actor in several films throughout the 1980s, Roshan made his film debut in a leading role in Kaho Naa... Pyaar Hai in 2000. His performance in the film earned him Filmfare Awards for Best Actor and Best Male Debut. He followed it with leading roles in Fiza and Mission Kashmir (both released in 2000) and a supporting part in the blockbuster Kabhi Khushi Kabhie Gham (2001)",
    		FilmStarBio2 = "Following through with several unnoticed performances from 2002 to 2003, he starred in the blockbusters Koi... Mil Gaya (2003) and its sequel Krrish (2006), both of which won him numerous Best Actor awards.[3] Roshan received his third Filmfare Award for Best Actor in 2006 for his performance in the action film Dhoom 2, and his fourth for Jodhaa Akbar[4] for which he was also awarded at the Golden Minbar International Film Festival. He later received further acclaim for his work in Guzaarish (2010), Zindagi Na Milegi Dobara (2011) and Agneepath (2012), his biggest commercial success so far. These accomplishments have established him as a leading contemporary actor of Hindi cinema.",
    	});
    }
    • Add private dictionary where string is act as key and FlimStarInformationModal as value.
    • On Button Click event, Add OnCreateTabHostControl which will create TabHost on the fly
    • Add CreateFlimStarInformationDict method, which contain our dummy data, to be used while displaying data in tab. 
    • I have added following images under Resources->Drawable

    Image 6 Image 7 Image 8
    Amitabh Bachchan Shahrukh Khan Hrithik Roshan

  8. Now it time add following code to create TabHost and attaching the tabpages with it. I will explain code step by step below:-
    C#
    LocalActivityManager localActMgr = new LocalActivityManager (this, false);
    localActMgr.DispatchCreate (bundle);
    
    TabHost tabHost = FindViewById<tabhost> (Resource.Id.tabHost1);
    tabHost.Setup (localActMgr);
    
    TabHost.TabSpec tabSpec = null;
    Intent intent = new Intent ();
    intent.SetFlags (ActivityFlags.NewTask);
    intent.SetClass(this,typeof(flimStarUI));
    tabSpec = tabHost.NewTabSpec ("Amitabh");
    tabSpec.SetContent (intent);
    tabSpec.SetIndicator ("Amitabh");
    tabHost.AddTab (tabSpec);
    • First create LocalActivityManager object, which will used by TabHost to setup itself, with this step, app will throw exception. 
    • Now, find TabHost control using FindViewById method and call Setup method by passing LocalActivityManager Object.
    • Now add Intent object, type of flimStarUI, which will set content of tab page
    • Now fill TabHost.TabSpec with intent content and label indicator as string e.g. "Amitabh"  above. 
    • Add tab in TabHost container using AddTab method. Tab Button would automatically created in TabWidget with Indicator string as label.

  9. Now Build and Run the application, on Clicking "On TabHost Control" button, you can see following, Volia!, Our Biography app is not working!.
    Image 9

    Figure "FirstRun"

    Now our raw TabHost container visible on screen, with tabbed button containing label of Actor's name. However no data in content pages, except the dummy screen we created for flimStarUI screen.

  10. Now, for sending information from Main Activity to tabbed content, we have use
    BroadReceiver
    derived class to start communication between activities. So I have added following class :-
    C#
    public class MainActivityBroadcast : BroadcastReceiver
    {
    	public event Action<Context,Intent> actionRecv;
    
    	#region implemented abstract members of BroadcastReceiver
        public override void OnReceive (Context context, Intent intent)
    	{
    	   if (this.actionRecv != null) {
    				this.actionRecv (context, intent);
    			}
    	}
    	#endregion
    }
  11. Add following code in flimStarUI to register and start receiving events across the application.
    Add Following class variables in the class.
    C#
    MainActivityBroadcast broadcastRecv;
    const string ACTION_NEW_TABSELECTED = "NEWTABSELECTED";
    In OnCreate method add following code :-
    C#
    broadcastRecv = new MainActivityBroadcast ();
    broadcastRecv.actionRecv += OnBroadCastReceived;
    RegisterReceiver(broadcastRecv,
    			     new IntentFilter(ACTION_NEW_TABSELECTED));
    Here, create MainActivityBroadcast object and assign actionRecv with delegate and using RegisterReceiver method, register ACTION_NEW_TABSELECTED event and associated with broadcastRecv Object.
    Now add following code in OnBroadCastReceived method :-
    C#
    void OnBroadCastReceived (Context arg1, Intent arg2)
    {
        if(arg2!=null)
        {
    	    var txtFilmStarInfo = FindViewById<TextView> (Resource.Id.txtFilmStar);
    	    var txtFilmStarBio1 = FindViewById<TextView> (Resource.Id.txtFilmStarBio1);
    	    var txtFilmStarBio2 = FindViewById<TextView> (Resource.Id.txtFilmStarBio2);
    	    var ivFilmStar = FindViewById<ImageView> (Resource.Id.ivFilmStar);
    
    
    	    txtFilmStarInfo.Text = arg2.GetStringExtra("FilmStarName");
    	    ivFilmStar.SetImageResource(arg2.GetIntExtra("FlimStarImageID",-1));
    	    txtFilmStarBio1.Text = arg2.GetStringExtra("FilmStarBio1");
    	    txtFilmStarBio2.Text = arg2.GetStringExtra("FilmStarBio2");
        }
    }

    In this method, we will find TextView and ImageView control and assign them values send from MainActivity. In end add following code, to register and unregister receiver OnResume and OnPause Handler. This is done to avoid receiving any event at the time it’s in pause state and also save scarce mobile resources.

    C#
     protected override void OnResume ()
    {
    	base.OnResume ();
    	RegisterReceiver(broadcastRecv,
    	                 new IntentFilter(ACTION_NEW_TABSELECTED));
    }
    
    protected override void OnPause ()
    {
    	base.OnPause ();
    	UnregisterReceiver(broadcastRecv);
    }
  12. Before sending message to flimStarUI, you have to handle Tab Button Click for tab changes. For that, you need to implement TabHost.IOnTabChangeListener in MainActivity. This put TabHost.IOnTabChangeListener.OnTabChanged method in class, which provides tabId as parameter. Add following code in OnTabChanged method :- 
    C#
    void TabHost.IOnTabChangeListener.OnTabChanged (string tabId)
    {
    	SendMessage (tabId);
    }
    
    void SendMessage (string tabId)
    {
    	var newTweetsIntent = new Intent (ACTION_NEW_TABSELECTED);
    	var cItem = dictFlimStarInfo[tabId];
    	newTweetsIntent.PutExtra ("FilmStarName", cItem.FilmStarName);
    	newTweetsIntent.PutExtra("FlimStarImageID", cItem.FlimStarImageID);
    	newTweetsIntent.PutExtra("FilmStarBio1", cItem.FilmStarBio1);
    	newTweetsIntent.PutExtra("FilmStarBio2", cItem.FilmStarBio2);
    	SendBroadcast (newTweetsIntent);
    }

    MainActivity class contain dictFlimStarInfo dictionary based on tabid as key and related information as value. So what we have done in SendMessage method is as follow

    • Create Intent with “NEWTABSELECTED” as action  
    • Add information in Intent, using PutExtra 
    • Using SendBroadcast dispatch intent to Activity

    After all this, Call TabHost.SetOnTabChangedListener (this) (Since MainActivity Implements TabHost.IOnTabChangeListener) method to setup TabChanged listener.


  13. Now Build and Run! (In Potrait Mode)
    Image 10     Image 11
    Android 3.4 Inch     Android 4 inch.
  14. Running application in Landscape Mode 

    Image 12
    Android Device 7 Inch: Landscape

Putting Icon on TabButton

  1. Now for Adding icon on Tabbutton, add icon corresponding to actor name (First row for active and second row contain in-active state icons) :-
    Image 13 Image 14 Image 15
    Amitabh Bachan Shahrukh Khan Hrithik Roshan
    Image 16 Image 17 Image 18

  2. Now change TabSpec.SetIndicator method to include reference to above images.
    C#
    tabSpec.SetIndicator ("Hrithik",Resources.GetDrawable (Resource.Drawable.Hrithik_ico));
    
    Resources.GetDrawable() method returns Drawable object based on Drawable Resource, which is used to display icon in Tab Button.
  3. Build and Run, you can see Images visible at top :-
    Image 19

    This example utilized single image for both selected and un-selected state. Now if you want different image for both, you have to use XML to define its state.

  4. Now to include disabled image, when Tab is unselected. We can use selector based XML to define icon for different states. read more about selector here
    XML
    <?xml version="1.0" encoding="UTF-8" ?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <!-- When selected, use grey -->
        <item android:drawable="@drawable/Hrithik_ico"
              android:state_selected="true" />
        <!-- When not selected, use white-->
        <item android:drawable="@drawable/Hrithik_icod" />
    </selector>

    Here, Hrithik_ico will be displayed, when tab is active and Hrithik_icod (disabled) will be displayed when it's inactive. Similarly make XML for rest of Actor’s.

  5. Now do the following changes in code listed in step 2 :-
    C#
    tabSpec.SetIndicator ("Hrithik",Resources.GetDrawable (Resource.Drawable.selectHrithik));
    

    Now instead of icon resource use XML resource

  6. Build and Run :-
    Image 20

Points of Interest

I have used MonoAndroid for C# and Xamarin Studio to build this tutorial.  Watch out, if I continue learning it, you can expect more articles coming soon. 

Though Xamarin Studio is proprietary software, however they provide free starter version to built, test and publish android application. I am using same for my learning. 

Articles in this series!

Tips/Tricks in this Series

History  

  • 13-Aug-2013: First Version
  • 14-Aug-2013: Added section for placing icon on Tab Buttons
  • 22-Aug-2013: Added section "Other Articles in this series"
  • 06-Sept-2013: Added section "Tips/Tricks in this series" 
  • 11-Oct-2013 : Updated article section 
  • 05-Nov-2013: Updated article section 
  • 22-Nov-2013: Updated other article section

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)