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

MonoAndroid: Using Fragments in mobile app

5.00/5 (8 votes)
21 Nov 2013CPOL6 min read 51.8K   974  
Using Fragments in your mobile application.

Introduction

This is the fourth article in series of MonoAndroid, the previous ones are generic BaseAdapter, android Grid View and android TabHost Container.

In this article I am going to demonstrate Fragment (dictionary meaning “A small part broken off or detached”). If you understand/remember User Control in desktop programming, its similar to it. If you not, consider Fragment as independent code/UI component which can be plugged and run independently.

Fragment needs a container to run. Now you can either use FrameLayout and provide it with Fragment Object or use Fragment tag at design time, by providing class property with Fragment class name. I will explain it further.

Fragment can be further explained with following diagram. In which first layout we are using three Fragment in single screen, similarly showing different layout based on Fragments.

 Image 1 

In this article we will create Software Developer information app. Fragments first introduced in Honeycomb version of Android.

Step By Step we move forward

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


    Image 2
    Figure 1: Creating Android Project!

  2.  
  3. Once Project is created, Open Resource Folder->Layout and Add two new file of type FragmentLeft.axml and FragmentRight.axml, this will act to different fragment, which we will combined in single activity further.

  4. Add following code in FragmentLeft layout file
    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">
        <TextView
            android:text="Medium Text"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:id="@+id/fl_textVDesigination" />   
        <ScrollView
            android:minWidth="25px"
            android:minHeight="25px"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:id="@+id/scrollView1"
            android:layout_weight="0" >
             <TextView
            android:text="Small Text"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:id="@+id/fl_textVDesc" />
            </ScrollView>
        <Button
            android:text="Next"
            android:layout_width="fill_parent"
            android:layout_height="38.0dp"
            android:id="@+id/fl_Next"/>
    </LinearLayout>

    In above view, I have two text view, one of which will act as header and other will contain information based on header and one button which will facilitate moving records.


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

    Image 3 

    Figure : Designer view of GridView custom item 

       
  5. Create Folder Fragments (this I am doing to segregate different code part) and add FragmentLeft.cs file, which will act as code-behind file for above created FragmentLeft.axml file. Add following code there:-
    C#
    internal class FragmentLeft : Fragment
    {
    	int _Index = 0;
    	TextView textDesg,textDesc;
    	string[] arrInformation = new string[]
    {
      "Software Developer",
      "A software developer is a person concerned with facets of the software development process. Their work includes researching, designing, implementing, and testing software.",
      "Lead Programmer",
      "A lead programmer is a software engineer in charge of one or more software projects. When primarily contributing in a high-level enterprise software design role, the title Software Architect (or similar) is often used"
    };
    
     public override void OnCreate (Bundle savedInstanceState)
     {
       base.OnCreate (savedInstanceState);
       // Create your fragment here
     }
    
     public override View OnCreateView (LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState)
      {
    	var view = inflater.Inflate(Resource.Layout.FragmentLeft, container, false);
    	textDesg = view.FindViewById<TextView>(Resource.Id.fl_textVDesigination);
            textDesc = view.FindViewById<TextView>(Resource.Id.fl_textVDesc);
        
            SetInformationOnText (textDesg, textDesc);
    	return view;
      }
    
    
     void SetInformationOnText (TextView textDesg, TextView textDesc)
     { 
    	textDesg.Text = arrInformation [_Index];
    	textDesc.Text = arrInformation [_Index + 1];
    	_Index = (_Index == 2) ? 0 : 2;
     }
    }

    Here, I have derived class from the Fragment class, have done following changes :-

    • Now override Fragment ::OnCreateView (), and inflate "Resource.Layout.FragmentLeft" layout in the container, passed as parameter to method.
    • Now get object of textview of Resource.Id.fl_textVDesigination and Resource.Id.fl_textVDesc using FindViewById and store in class variable. 
    • I have added hard coded string array in class, where even number location contain header text and odd number location contain the description.
    • Using SetInformationOnText function, update the text views.

  6. Now add model class by name FragmentModel. here is code FragmentModel class. (Similar to Step2, instead of adding Layout file, add C# class file) 
    C#
    public class FragmentModel
    {
       public string Name {get;set;}
       public string Desigination {get;set;}
    }

    Each object of above class will act as content for FragmentRight layout.

  7. Add following code in FragmentRight layout file
    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"
        android:minWidth="25px"
        android:minHeight="25px">
        <ListView
            android:minWidth="25px"
            android:minHeight="25px"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:id="@+id/fr_ListView1" />
    </LinearLayout>

    In this layout, I have added ListView, which will display the list of people and there designation in some fictitious organizations.

  8. Create ListVwAdapter, which derived from BaseAdapter<FragmentModel> , and implement its abstract methods. Add following code in this file.
    C#
    public class ListVwAdapter: BaseAdapter<FragmentModel>
    {
    	Activity _Context;
    	List<FragmentModel> _lstFragments;
    
    	public ListVwAdapter (Activity c, List<FragmentModel> lstFragments)
    	{
    		_Context = c;
    		_lstFragments = lstFragments;
    		
    	}
    
    	#region implemented abstract members of BaseAdapter
    	public override long GetItemId (int position)
    	{
    		return position;
    	}
    
     public override View GetView (int position, View convertView, ViewGroup parent)
     {
       var item = this [position];
       
       if (convertView == null)
         convertView = _Context.LayoutInflater.Inflate (Android.Resource.Layout.SimpleListItem2, parent, false);
    
      convertView.FindViewById<TextView> (Android.Resource.Id.Text1).Text = item.Name;
      convertView.FindViewById<TextView> (Android.Resource.Id.Text2).Text = item.Desigination;
    
    	return convertView;		
     }
    public override int Count {
    	get {
    		return _lstFragments != null ? _lstFragments.Count : -1;
    	}
    }
    	#endregion
    	#region implemented abstract members of BaseAdapter
    	public override FragmentModel this [int index] {
    		get {
    			return _lstFragments != null ? _lstFragments[index] : null;
    		}
    	}
    	#endregion
    }

    You can read more about create generic baseadapter and binding it to ListView here. Only difference from article is that, we are using Android

    SimpleListItem2
    and update Text1 and Text2 with Name and Designation.

  9. Similarly add code-behind file for FragmentRight.axml by name FragmentRight.xml and derived it with Fragment.
    C#
    internal class FragmentRight : Fragment
    {
    	List<FragmentModel> _lstFragmentDemo = new List<FragmentModel> ();
    
     public override void OnCreate (Bundle savedInstanceState)
     {
    	base.OnCreate (savedInstanceState);
    	_lstFragmentDemo.Add (new FragmentModel () {
    	 Name = "Alok Gupta", Desigination = "Snr Software Engineer"
    	});
    
    	_lstFragmentDemo.Add (new FragmentModel () {
       	 Name = "Jasdeep Singh", Desigination = "Snr Auditor (Information)"
    	});
    
    	_lstFragmentDemo.Add (new FragmentModel () {
    	  Name = "Ashish Srivastava", Desigination = "Software Test Engineer"
    	});
    
    	_lstFragmentDemo.Add (new FragmentModel () {
    	  Name = "Hariharan Ramchandran", Desigination = "Product Architect"
    	});
    }
    
    public override View OnCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
     { 
    	var view = inflater.Inflate(Resource.Layout.FragmentRight, container, false);
    	var listView = view.FindViewById<ListView>(Resource.Id.fr_ListView1);
    	listView.Adapter = new ListVwAdapter (this.Activity, _lstFragmentDemo);
    	return view;
     }
    }

    In above code we have created List of FragmentModel and provided it some hardcoded values

    In OnCreateView function, inflate FragmentRight layout and create ListVwAdapter adapter and bind it to listview object.

  10. 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" />
        <LinearLayout
            android:orientation="horizontal"
            android:minWidth="25px"
            android:minHeight="25px"
            android:layout_width="fill_parent"
            android:layout_height="match_parent"
            android:id="@+id/linearLayout1">
            <FrameLayout
                android:minWidth="25px"
                android:minHeight="25px"
                android:layout_width="136.0dp"
                android:layout_height="fill_parent"
                android:id="@+id/main_FragmentContainerLeft"
                android:layout_marginRight="6.7dp" />
            <fragment
                android:minWidth="25px"
                android:minHeight="25px"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:id="@+id/main_FragmentContainerRight"
                class="monofragmentdemo.FragmentRight" />
        </LinearLayout>
    </LinearLayout>

    First add Horizontal LinearLayout in the axml file.

    • Add FrameLayout , it will act as container for Fragment, when adding fragment through code.
    • Use Fragment tag for adding fragment at design time. You need to pass full qualified classname in fragments class property. One thing is to remember except class name, everything should be in lowercase e.g. if fully qualified name is “MonoFragmentDemo.FragmentRight”, you have to pass “monofragmentdemo.FragmentRight”  

    Now following is the code of MainActivity.cs file :-

    C#
    public class MainActivity : Activity
    {
    	int count = 1;
    
    	protected override void OnCreate (Bundle bundle)
    	{
    		base.OnCreate (bundle);
    
    		// Set our view from the "main" layout resource
    		SetContentView (Resource.Layout.Main);
    
    		// Get our button from the layout resource,
    		// and attach an event to it
    		Button button = FindViewById<Button> (Resource.Id.myButton);
    
    		if(button != null)
    		button.Click += delegate {
    			button.Text = string.Format ("{0} clicks!", count++);
    		};
    
    		var newFragment = new FragmentLeft ();
    		var ft = FragmentManager.BeginTransaction ();
    		ft.Add (Resource.Id.main_FragmentContainerLeft, newFragment);
    		ft.Commit ();
    	}
    }

    We already added one fragment at design level , now for adding fragment through coding, we will use FragmentManager. We will start the transaction using

    BeginTransaction
    method, add framelayout container and object of fragment we wish to show on screen and in end calling commit() to make available for user.

  11. Now Build and Run the application,
    In 4 Inch Screen In 3.4 Inch Screen
    Image 4 Image 5
     

    Figure "FirstRun"

    Now everything is working except the button, because we haven’t coded for that yet.

  12. For adding button click support, you have to implement View.IOnClickListener interface. Following code changes are necessitated to include button click event support

    In OnCreateView method :-

    C#
    var nextButton = view.FindViewById<Button>(Resource.Id.fl_Next);
    if (nextButton != null)
    	nextButton.SetOnClickListener (this);

    In View.IOnClickListener.OnClick (Implemented) method :-

    C#
    #region IOnClickListener implementation
    
    	void View.IOnClickListener.OnClick (View view)
    	{
    		SetInformationOnText (textDesg, textDesc);
    	}
    
    #endregion
  13. Now Build and Run the application again
    In 4 Inch Screen After Clicking  "Next" Button
     Image 6  Image 7

    You can see the FragmentLeft text changes on Button Click.

  14. Now we can have different layout based on different screen sizes. If you refer screenshot above we have same layout on 3.4 and 4 inch device emulator.

    Now in case, you are building some application which is wide or big, In that case it difficult for user, to view mobile app properly. So it becomes necessary for mobile phone developer to have different layout for different mobile app to make its application more popular.

    So now add layout-ldpi (layout for low density screen) folder under Layout folder. You can read more about different screen sizes on android website

    Image 8
  15. Now copy main.axml from main layout folder and paste it layout-ldpi folder. I have done some changes in user design, The code is 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">
        <LinearLayout
            android:orientation="vertical"
            android:minWidth="25px"
            android:minHeight="25px"
            android:layout_width="fill_parent"
            android:layout_height="match_parent"
            android:id="@+id/linearLayout1">
            <FrameLayout
                android:minWidth="25px"
                android:minHeight="25px"
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:id="@+id/main_FragmentContainerLeft"
                android:layout_marginBottom="6.7dp" />
            <fragment
                android:minWidth="25px"
                android:minHeight="25px"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:id="@+id/main_FragmentContainerRight"
                class="monofragmentdemo.FragmentRight" />
        </LinearLayout>
    </LinearLayout>

    Here I have removed the Button from layout and instead of horizontal linear layout, we will use vertical linear layout. Now designer for Main.axml looks like this :-

    Image 9

  16. Now Build and Run!. Android System is very intelligent, it will select the appropriate layout based on screen size. In 4 Inch emulator it will run as usual and in 3.4" inch with new layout which we have create above!.
    In 3_4 Inch Screen After Clicking "Next" Button
     Image 10  Image 11

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. 

Other articles in this series!

Tips/Tricks in this Series

History  

  • 21-Aug-2013 : First Version
  • 22-Aug-2013 : Some editing, some grammar mistakes rectified  
  • 06-Sept-2013 : Updated tips and tricks section 
  • 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)