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
In this article we will create Indian FlimStar Biography app based on TabHost
Step By Step we move forward
`
- Create Android application by selecting New ->Solutions and
provide its name “
TabHostDemo
”
Figure 1: Creating Android Project!
- Once Project is created, Open Resource Folder->Layout and Add
new file of type tabItemLayout.axml
Figure 2: Selecting New File!
Figure 3: Select Layout file
- Add Following code in layout file
="1.0"="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 :-
Figure 4: Designer view of GridView custom item
- 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);
}
Here we associated the flimStarUI with tabItemLayout.axml, using SetContentView
and passing resource id of layout file.
- 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)
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
.
- Now in Main.axml layout file, code look like as follow:-
="1.0"="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.
Dictionary<string,FlimStarInformationModal> dictFlimStarInfo = new Dictionary<string, FlimStarInformationModal>();
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
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
|
|
|
Amitabh Bachchan
| Shahrukh Khan
| Hrithik Roshan
|
- Now it time add following code to create TabHost and attaching the tabpages with it. I will
explain code step by step below:-
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.
- Now Build and Run the application, on Clicking "On TabHost Control" button,
you can see following, Volia!, Our Biography app is not working!.
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.
- 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 :-
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
}
- Add following code in
flimStarUI
to register and start receiving events across the
application.
Add Following class variables in the class.
MainActivityBroadcast broadcastRecv;
const string ACTION_NEW_TABSELECTED = "NEWTABSELECTED";
In OnCreate
method add following code :-
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 :-
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.
protected override void OnResume ()
{
base.OnResume ();
RegisterReceiver(broadcastRecv,
new IntentFilter(ACTION_NEW_TABSELECTED));
}
protected override void OnPause ()
{
base.OnPause ();
UnregisterReceiver(broadcastRecv);
}
- 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 :-
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.
- Now Build and Run!
(In Potrait Mode)
|
|
|
Android 3.4 Inch
|
| Android 4 inch.
|
- Running application in Landscape Mode
Android Device 7 Inch: Landscape
Putting Icon on TabButton
- Now for Adding icon on Tabbutton, add icon corresponding to actor name (First row for active and second row contain in-active state icons) :-
|
|
|
Amitabh Bachan
| Shahrukh Khan
| Hrithik Roshan
|
| | |
- Now change TabSpec.SetIndicator method to include reference to above images.
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.
- Build and Run, you can see Images visible at top :-
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.
- 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
="1.0"="UTF-8"
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/Hrithik_ico"
android:state_selected="true" />
<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.
- Now do the following changes in code listed in step 2 :-
tabSpec.SetIndicator ("Hrithik",Resources.GetDrawable (Resource.Drawable.selectHrithik));
Now instead of icon resource use XML resource
- Build and Run :-
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