MonoAndroid: Using Fragments in mobile app
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.
In this article we will create Software Developer information app. Fragments first introduced in Honeycomb version of Android.
Step By Step we move forward
`- Create Android application by selecting New ->Solutions and
provide its name “
MonoFragmentDemo
”
Figure 1: Creating Android Project! - 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.
- Add following code in FragmentLeft layout file
<?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 :-Figure : Designer view of GridView custom item
- 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:-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.
- Now override
- Now add model class by name FragmentModel. here is code FragmentModel
class. (Similar to Step2, instead of adding Layout file, add C#
class file)
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.
- Add following code in FragmentRight layout file
<?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.
- Create ListVwAdapter, which derived from BaseAdapter<FragmentModel> , and implement
its abstract methods. Add following code in this file.
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 updateText1
andText2
with Name and Designation. - Similarly add code-behind file for FragmentRight.axml by name FragmentRight.xml
and derived it with
Fragment
.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. - Now in Main.axml layout file, code look like as follow:-
<?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 :-
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 usingBeginTransaction
method, add framelayout container and object of fragment we wish to show on screen and in end callingcommit
() to make available for user. - Now Build and Run the application,
In 4 Inch Screen In 3.4 Inch Screen
Figure "FirstRun"
Now everything is working except the button, because we haven’t coded for that yet.
- For adding button click support, you have to implement
View.IOnClickListener
interface. Following code changes are necessitated to include button click event supportIn
OnCreateView
method :-var nextButton = view.FindViewById<Button>(Resource.Id.fl_Next); if (nextButton != null) nextButton.SetOnClickListener (this);
In
View.IOnClickListener.OnClick
(Implemented) method :-#region IOnClickListener implementation void View.IOnClickListener.OnClick (View view) { SetInformationOnText (textDesg, textDesc); } #endregion
- Now Build and Run the application again
In 4 Inch Screen After Clicking "Next" Button You can see the FragmentLeft text changes on Button Click.
-
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. - 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 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 :-
- 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
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!
- MonoAndroid: Writing custom generic BaseAdapter in C#
- MonoAndroid: Using GridView in your mobile application
- MonoAndroid: Using TabHost in your mobile applications
- MonoAndroid: Using dotnet webservice (ASMX)
- MonoAndroid: Calling secondary activity
- MonoAndroid: Using Started Service
- MonoAndroid: Writing ExpandableListView amd BaseExpandableListAdapter in C#
- MonoAndroid: Using AlertDialog
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