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
="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">
<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);
}
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 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
="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"
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 update Text1
and Text2
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:-
="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" />
<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);
SetContentView (Resource.Layout.Main);
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.
- 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 support
In 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
="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">
<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!
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