User Tools

Site Tools


android-labs-s14:class-05

Class 05

In this class, we'll be learning about Fragments.


Demo-1

We'll see a small demo of the app we're going to build next.

Fragments

  • A Fragment represents a behavior or a portion of user interface in an Activity.
  • Fragments enable more modular activity design, making it easier to adapt an application to different screen orientations and multiple screen sizes.
  • Fragments must be embedded in activities; they cannot run independent of activities.
  • You can combine multiple fragments in a single activity to build a multi-pane UI and reuse a fragment in multiple activities.

(Image source: developer.android.com)

  • You can think of a fragment as a modular section of an activity, which has its own lifecycle, receives its own input events, and which you can add or remove while the activity is running (sort of like a “sub activity” that you can reuse in different activities).

(Image source: developer.android.com)

Exercise

Let's build this Board application.

This app will be using two fragments:

  1. Pane for Buttons
  2. Pane for Canvas

Step 00: Create Android Project (Min API Level: 11)

Start by creating an Android Project with minimum API Level = 11, as Fragment is available only on or after that. To use Fragments for API Level < 11, you have to use a compatibility package provided by Android. See Support Library for more details.

Step 01: UI for the fragments

Now, create two Android XML files in res/layout as UI for the two fragments:

  1. fragment_01.xml : Having two buttons inside a Linear/Relative Layout
  2. fragment_02.xml : Having a TextView in the center
fragment_01.xml
<?xml version="1.0" encoding="utf-8"?>
 
<RelativeLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/grey" >
 
    <Button
        android:id="@+id/btn_one_create_new"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/one_create_new"
        android:layout_alignParentTop="true"
        android:layout_marginTop="@dimen/btn_margin_vertical"
        android:layout_marginBottom="@dimen/btn_margin_vertical"
        android:layout_marginLeft="@dimen/btn_margin_horizontal"
        android:layout_marginRight="@dimen/btn_margin_horizontal"
        android:onClick="onButtonClick" />
 
    <Button 
        android:id="@+id/btn_one_open_existing"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/one_open_existing"
        android:layout_below="@id/btn_one_create_new"
        android:layout_marginTop="@dimen/btn_margin_vertical"
        android:layout_marginBottom="@dimen/btn_margin_vertical"
        android:layout_marginLeft="@dimen/btn_margin_horizontal"
        android:layout_marginRight="@dimen/btn_margin_horizontal"
        android:onClick="onButtonClick" />
 
</RelativeLayout>
fragment_02.xml
<?xml version="1.0" encoding="utf-8"?>
 
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
 
    <!-- Welcome Title -->
   	<TextView
       android:id="@+id/textview_welcome"
       android:layout_height="match_parent"
       android:layout_width="match_parent"
       android:gravity="center"
       android:text="@string/two_welcome"
       android:textSize="@dimen/textsize_welcome_title"
       android:textStyle="bold" />
 
</LinearLayout>

You must be observing errors in these xml files as some of the values in them are not yet defined. We've to define them in different xml files in res/values directory.

colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- Feel free to play with the values here -->
 
    <color name="light_grey">#E0E0E0</color>
    <color name="grey">#D0D0D0</color>
 
</resources>
dimens.xml
<resources>
    <!-- Feel free to play with the values here -->
 
    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>
 
    <dimen name="btn_margin_vertical">30dp</dimen>
    <dimen name="btn_margin_horizontal">10dp</dimen>
 
    <dimen name="textsize_welcome_title">24sp</dimen>
 
</resources>
strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- Feel free to play with the values here -->
 
    <string name="app_name">Board</string>
    <string name="action_settings">Settings</string>
    <string name="hello_world">Hello world!</string>
 
    <string name="one_create_new">Create New</string>
    <string name="one_open_existing">Open Existing</string>
    <string name="one_select_board">Select a Board</string>
 
    <string name="two_welcome">Welcome to Board!</string>
    <string name="two_drawing">Name Your Drawing</string>
 
</resources>

Step 02: Add the above fragments to Main Screen

For Phones

For phones, we only want the fragment (fragment_01.xml) with the buttons on the Main Screen.

Hence, Main screen layout, which is layout/activity_main.xml, should look something like below:

layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
 
<!-- PHONE -->
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:baselineAligned="false"
    android:background="@color/light_grey" >
 
    <!-- Fragment One only -->
   	<fragment
        android:id="@+id/fragment_one"
        android:name="com.example.board.FragmentOne"
        android:layout_height="match_parent"
        android:layout_width="0dp"
        android:layout_weight="1" />
 
</LinearLayout>
For Tablets

In case of a Tablet device, we want both fragments to show up in the main screen.

  • To have a different layout for tablets, we have to add another folder layout-large inside res folder (See 'Using Configuration qualifiers' section for more details).
  • Now, create an Android xml file with the same name as used for Main screen xml file (i.e., activity_main.xml), which should have both the fragments inside a Linear/Relative Layout.
layout-large/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
 
<!-- TABLET -->
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:baselineAligned="false"
    android:background="@color/light_grey" >
 
   <!-- Fragment One -->
   <fragment
        android:id="@+id/fragment_one"
        android:name="com.example.board.FragmentOne"
        android:layout_height="match_parent"
        android:layout_width="0dp"
        android:layout_weight="1" />
 
   <!-- Fragment Two -->
   <fragment
        android:id="@+id/fragment_two"
        android:name="com.example.board.FragmentTwo"
        android:layout_height="match_parent"
        android:layout_width="0dp"
        android:layout_weight="3" />
 
</LinearLayout>

Step 03: Create Fragment classes for both the fragments

You may have noticed that inside the <fragment> xml tag in activity_main.xml file, we have specified a class that will represent this fragment. So, let's create those classes -

  1. FragmentOne.java: corresponding to fragment_01.xml
  2. FragmentTwo.java: corresponding to fragment_02.xml
  • Create classes FragmentOne.java and FragmentTwo.java inside src/com.example.board package, extending Fragment class. Both of these classes should implement onCreateView() method, as shown below:
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
	{
		return inflater.inflate(R.layout.<CORRESPONDING_LAYOUT>, container, false);
	}

A little background on onCreateView() method:

The system calls **onCreateView()** method when it's time for the fragment to draw its user interface for the first time. 
To draw a UI for your fragment, you must return a View from this method that is the root of your fragment's layout.
You can return null if the fragment does not provide a UI.

Now, if at this point, you launch your App on your device/emulators, you should see our basic UI skeleton on their screens.

Step 04: [Phone Only] Create another screen

  • On Phone, we need to have another screen containing fragment_02.xml as its UI. So, for that, first create an Android XML file activity_drawing.xml inside res/layout folder. This xml file will only include fragment_02 inside a LinearLayout.
activity_drawing.xml
<?xml version="1.0" encoding="utf-8"?>
 
<!-- PHONE -->
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:baselineAligned="false"
    android:background="@color/light_grey" >
 
    <!-- Fragment Two only -->
    <fragment
        android:id="@+id/fragment_two"
        android:name="com.example.board.FragmentTwo"
        android:layout_height="match_parent"
        android:layout_width="0dp"
        android:layout_weight="1" />
 
</LinearLayout>
  • Now, create a class DrawingActivity.java inside src/com.example.board, extending Activity class. Set the content view of DrawingActivity class to activity_drawing.xml.
  • Again, don't forget to register DrawingActivity.java in AndroidManifest.xml.

Step 04: Implement Button Callbacks

Now, we just need to implement onButtonClick callbacks for the two buttons on Main screen. On Phone, clicking on 'Create New' button should lead us to DrawingActivity, whereas on Tablet, it should just show up a Toast Message (for now).

To identify, whether the application is being run on Phone or Tablet, just look out for presence of ''FragmentTwo'' object in ''MainActivity'' class.
In case of Tablet, ''FragmentTwo'' object would have been initialized as it is part of its Main screen UI.

So, onButtonClick method can be implemented as follows:

onButtonClick()
	public void onButtonClick(View v)
	{
		FragmentTwo fragmentTwo = (FragmentTwo) getFragmentManager().findFragmentById(R.id.fragment_two);
 
		switch(v.getId())
		{
		case R.id.btn_one_create_new:
 
			if (fragmentTwo == null)	// PHONE!
			{
				// Need to launch another activity
				Intent i = new Intent(this, DrawingActivity.class);
				startActivity(i);
			}
			else				// TABLET!
			{
				// Do nothing right now, and just show up a toast.
				Toast.makeText(this, "Will be implemented later", Toast.LENGTH_SHORT).show();
			}
 
			break;
 
		case R.id.btn_one_open_existing:
 
			Toast.makeText(this, "Will be implemented later", Toast.LENGTH_SHORT).show();
 
			break;
 
		default:
		}
	}

Source Code

Available at Github.

android-labs-s14/class-05.txt · Last modified: 2014/02/19 03:00 by prakhar