This practical codelab is part of Unit 4: User Interaction in the DC3040/CS3040 module.
For the complete list of codelabs in the course, see Mobile Development Codelabs.
The user interface (UI) that appears on a screen of an Android-powered device consists of a hierarchy of objects called views. Every element of the screen is a View.
The View class represents the basic building block for all UI components. View is the base class for classes that provide interactive UI components, such as Button elements. A Button is a UI element the user can tap or click to perform an action.
You can turn any View, such as an ImageView, into a UI element that can be tapped or clicked. You must store the image for the ImageView in the drawables folder of your project.
In this practical, you learn how to use images as elements that the user can tap or click.
You should be able to:
drawable folder.ImageView elements in the layout editor.onClick() method to display a Toast message.onClick() handlers for the images to display different Toast messages.Fragment.In this practical, you create and build a new app starting with the Basic Activity template that imitates a dessert-ordering app. The user can tap an image to perform an action—in this case display a Toast message—as shown in the figure below. The user can also tap a shopping-cart button to proceed to the next Activity.

You can make a view clickable, as a button, by adding the android:onClick attribute in the XML layout. For example, you can make an image act like a button by adding android:onClick to the ImageView.
In this task you create a prototype of an app for ordering desserts from a café. After starting a new project based on the Basic Activity template, you modify the "Hello World" TextView with appropriate text, and add images that the user can tap.
activity_main.xml for the app bar and floating action button (which you don't change in this task), and content_main.xml which contains a ConstraintLayout containing a NavHostFragment (see the JetPack Navigation Codelab). The layout called fragment_first.xml contains the layour for FirstFragment and fragment_second.xml contains the layout for SecondFragment.fragment_first.xml and click the Design tab (if it is not already selected) to show the layout editor.TextView showing "Hello first fragment" in the layout and open the Attributes pane.Attribute | Value |
|
|
|
|
| Select |
|
|
This replaces the original android:id attribute for the TextView with the new id value textintro, changes the text, makes the text bold, and sets a larger text size of 24sp. All references to the previous id will have been updated so at this point but the app would NOT run because there is an onClick listener added to the Button in FirstFragment. We will fix this later.
textintroTextView to the top of the "Next" Button and als delete that Button., so that the TextView snaps to the top of the layout, and choose 8 (8dp) for the top margin as shown below.
"Droid Desserts" string in the TextView and enter intro_text as the string resource name.Three images (donut_circle.png, froyo_circle.png, and icecream_circle.png) are provided for this example, which you can download from Blackboard. As an alternative, you can substitute your own images as PNG files, but they must be sized at about 113 x 113 pixels to use in this example.
This step also introduces a new technique in the layout editor: using the Fix button in warning messages to extract string resources.
fragment_first.xml file, and click the Design tab (if it is not already selected).
Attribute | Value |
|
|
|
|
ImageView to the layout, choose the icecream_circle image for it, and constrain it to the bottom of the first ImageView and to the left side of the layout with a margin of 24 (24dp) for both constraints.
Attribute | Value |
|
|
|
|
ImageView to the layout, choose the froyo_circle image for it, and constrain it to the bottom of the second ImageView and to the left side of the layout with a margin of 24 (24dp) for both constraints.Attribute | Value |
|
|
|
|
, Warning icon in the upper right corner of the design panel (above the layout image) to open the warning pane, which should display warnings about hardcoded text:

String | Enter the following name: |
|
|
|
|
|
|
The layout of fragment_first.xml should now look like the figure below.

In this step you add a text description (TextView) for each dessert. Because you have already extracted string resources for the contentDescription fields for the ImageView elements, you can use the same string resources for each description TextView.
TextView element to the layout.ImageView and its top to the top of the donut ImageView, both with a margin of 24 (24dp).24dp). Enter donut_description for the ID field in the Attributes pane. The new TextView should appear next to the donut image as shown in the figure below.

text field by prefacing it with the @ symbol: @d. Click the string resource name (@string/donuts) which appears as a suggestion:
TextView that is constrained to the right side and top of the ice_creamImageView, and its right side to the right side of the layout. Enter the following in the Attributes pane:Attribute field | Enter the following: |
|
|
|
|
|
|
|
|
TextView that is constrained to the right side and top of the froyoImageView, and its right side to the right side of the layout. Enter the following in the Attributes pane:Attribute field | Enter the following: |
|
|
|
|
|
|
|
|

The XML layout for the content.xml file is shown below.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".FirstFragment">
<TextView
android:id="@+id/textintro"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/intro_text"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/donut"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="24dp"
android:contentDescription="@string/donuts"
android:src="@drawable/donut_circle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textintro" />
<ImageView
android:id="@+id/ice_cream"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="24dp"
android:contentDescription="@string/ice_cream_sandwiches"
android:src="@drawable/icecream_circle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/donut" />
<ImageView
android:id="@+id/froyo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="24dp"
android:contentDescription="@string/froyo"
android:src="@drawable/froyo_circle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/ice_cream" />
<TextView
android:id="@+id/textView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="24dp"
android:text="@string/donuts"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/donut"
app:layout_constraintTop_toTopOf="@+id/donut" />
<TextView
android:id="@+id/textView2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="24dp"
android:text="@string/ice_cream_sandwiches"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/ice_cream"
app:layout_constraintTop_toTopOf="@+id/ice_cream" />
<TextView
android:id="@+id/textView3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="24dp"
android:text="@string/froyo"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/froyo"
app:layout_constraintTop_toTopOf="@+id/froyo" />
</androidx.constraintlayout.widget.ConstraintLayout>
To make a View clickable so that users can tap (or click) it, add the android:onClick attribute in the XML layout and specify the click handler. For example, you can make an ImageView act like a simple Button by adding android:onClick to the ImageView. In this task you make the images in your layout clickable.
In this task you add each method for the android:onClick attribute to call when each image is clicked. In this task, these methods simply display a Toast message showing which image was tapped. (In another chapter you modify these methods to display another Fragment.)
strings.xml file. Expand res > values in the Project > Android pane, and open strings.xml. Add the following string resources for the strings to be shown in the Toast message:<string name="donut_order_message">You ordered a donut.</string>
<string name="ice_cream_order_message">You ordered an ice cream sandwich.</string>
<string name="froyo_order_message">You ordered a FroYo.</string>
displayToast() method to the end of MainActivity (before the closing bracket):public void displayToast(String message) {
Toast.makeText(getApplicationContext(), message,
Toast.LENGTH_SHORT).show();
}
Although you could have added this method in any position within MainActivity, it is best practice to put your own methods below the methods already provided in MainActivity by the template.Each clickable image needs a click handler-a method for the android:onClick attribute to call. The click handler, if called from the android:onClick attribute, must be public, return void, and define a View as its only parameter. Follow these steps to add the click handlers:
showDonutOrder() method to MainActivity. For this task, use the previously created displayToast() method to display a Toast message:/**
* Shows a message that the donut image was clicked.
*/
public void showDonutOrder(View view) {
displayToast(getString(R.string.donut_order_message));
}
The first three lines are a comment in the Javadoc format, which makes the code easier to understand and also helps generate documentation for your code. It is a best practice to add such a comment to every new method you create. For more information about how to write comments, see How to Write Doc Comments for the Javadoc Tool./**
* Shows a message that the ice cream sandwich image was clicked.
*/
public void showIceCreamOrder(View view) {
displayToast(getString(R.string.ice_cream_order_message));
}
/**
* Shows a message that the froyo image was clicked.
*/
public void showFroyoOrder(View view) {
displayToast(getString(R.string.froyo_order_message));
}
FirstFragment.java. In the onViewCreated method, there is a reference to R.id.button_first. We deleted that button earlier when we changed the layout in fragment_first.xml. Look for the following code (lines 23 to 27) and delete it.view.findViewById(R.id.button_first).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
NavHostFragment.findNavController(FirstFragment.this)
.navigate(R.id.action_FirstFragment_to_SecondFragment);
}
});
In this step you add android:onClick to each of the ImageView elements in the fragment_first.xml layout. The android:onClick attribute calls the click handler for each element.
android:onClick attribute to donutImageView. As you enter it, suggestions appear showing the click handlers. Select the showDonutOrder click handler as shown below:
<ImageView
android:id="@+id/donut"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="24dp"
android:contentDescription="@string/donuts"
android:src="@drawable/donut_circle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textintro"
android:onClick="showDonutOrder"/>
The last line (android:onClick="showDonutOrder") assigns the click handler (showDonutOrder) to the ImageView.
fragment_first.xml to conform to standards and make it easier to read. Android Studio automatically moves the android:onClick attribute up a few lines to combine them with the other attributes that have android: as the preface.android:onClick attribute to the ice_cream and froyoImageView elements. Select the showIceCreamOrder and showFroyoOrder click handlers. You can optionally choose Code > Reformat Code to reformat the XML code. The code should now look as follows:<ImageView
android:id="@+id/froyo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="24dp"
android:contentDescription="@string/froyo"
android:onClick="showFroyoOrder"
android:src="@drawable/froyo_circle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/ice_cream" />
<TextView
android:id="@+id/textView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="24dp"
android:text="@string/donuts"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/donut"
app:layout_constraintTop_toTopOf="@+id/donut" />
Note that the attribute android:layout_marginStart in each ImageView is set to 24dp, which means we have that margin size repeated throughout the file. This attribute determines the "start" margin for the ImageView, which is on the left side for most languages but on the right side for languages that read right-to-left (RTL).
<dimen name="margin_wide">24dp</dimen>
24dp values for the various android:layout_ attributes and replace them with the reference to the new dimension that you created above. When you type the @, the editor should pop up some suggestions and you should select @dimen/margin_wide as shown below:
Clicking the donut, ice cream sandwich, or froyo image displays a Toast message about the order, as shown in the figure below.

The solution code for this task can be found on Blackboard as solution
1 for DroidCafe.
If you implement your button onClick handlers by adding an onClick attribute to the Button tag in the XML, your Activity class must implement the handler method. This can get unmanageable if you have many screens and all of the click handler methods are in the Activity rather than the Fragment whose layout contains the button. It is much more cohesive to have each Fragment class implement its own onClick handlers.
We will now modify the first solution and move the onClick handlers for the clickable images into the FirstFragment class whose layout contains the clickable images.
displayToast to the FirstFragment class:private void displayToast(String message) {
Toast.makeText(getActivity().getApplicationContext(), message,
Toast.LENGTH_SHORT).show();
}
The difference to the similar method you created earlier in the MainActivity class is that the Fragment subclass does not have access to the getApplicationContext method, so we must call getActivity first.onViewCreated method in FirstFragment and add the following code to the end of the method:ImageView donutImage = view.findViewById(R.id.donut);
donutImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
displayToast("Fragment Donut Button Handler");
}
});
In this code, we use the findViewById method to find the Java object representing the donut button in the layout. Then we add a new OnClickListener to the button programmatically which requires us to implement the onClick method. For now, we just provide a Toast method to indictate that the Button was clicked.ImageView code with the id value @+id/donut.android:onClick attribute and its value from the donutImageView.android:onClick attributes should be deleted from fragment_first.xml.Toast strings from MainActivity to your new onClick methods in FirstFragment and delete the methods showFroyoOrder, showDonutOrder and showIceCreamOrder.ImageView donutImage = view.findViewById(R.id.donut);
donutImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
displayToast("You ordered a Donut");
}
});
ImageView iceCreamImage = view.findViewById(R.id.ice_cream);
iceCreamImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
displayToast("You ordered an Ice Cream Sandwich");
}
});
ImageView froyoImage = view.findViewById(R.id.froyo);
froyoImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
displayToast("You ordered a Frozen Yogurt");
}
});
When you click the floating action button with the email icon that appears at the bottom of the screen, the code in MainActivity displays a brief message in a drawer that opens from the bottom of the screen on a smartphone, or from the lower left corner on larger devices, and then closes after a few seconds. This is called a snackbar. It is used to provide feedback about an operation. For more information, see Snackbar.
Look at how other apps implement the floating action button. For example, the Gmail app provides a floating action button to create a new email message, and the Contacts app provides one to create a new contact. For more information about floating action buttons, see FloatingActionButton.
For this task you change the icon for the FloatingActionButton to a shopping cart and change the action for the FloatingActionButton to launch a new Activity.
, Shopping cart icon for the floating action button, and change the action for the FloatingActionButton to launch a new Fragment.
As you learned in another lesson, you can choose an icon from the set of icons in Android Studio. Follow these steps:

As you learned in a previous lesson, an Fragment represents a screen layout in your app in which can be loaded into view. You already have two fragments, FirstFragment.java and Secondragment.java. Now you add another Fragment called OrderFragment.java.
new destination icon and in the dialog window click Create new destination.public class OrderFragment extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_order, container, false);
}
}
We will now delete SecondFragment.java and its layout fragment_second.xml from the project as we will not be using it.
FirstFragment and SecondFragment and then right click and deleteSecondFragment from the graph too.fragment_second.xml and choose Refactor > Safe Delete.... Click OK in the Safe Delete dialog and then click Delete Anyway in the Usages Detected dialog. The usages are in SecondFragment.java which we are also about to delete. If you aren't sure where the file you are delting is referenced you can click View Usages to check.SecondFragment.java and choose Refactor > Safe Delete.... Click OK in the Safe Delete dialog. There should not be any further references to this file.In this step you change the action for the FloatingActionButton to display the new Fragment.
FirstFragment to control the use of the FloatingActionButton. Therefore we will copy the code the finds the FloatingActionbutton and sets its OnClickListener from MainActivity and paste that same code into the end of the onViewCreated method in FirstFragment.getActivity before findViewById:FloatingActionButton fab = getActivity().findViewById(R.id.fab);
FloatingActionButton in MainActivity.FloatingActionButton should still pop up the snack bar message, only now it is controlled from inside the FirstFragment.Now we will implement the action for the FloatingActionButton as controlled by the Firstfragment to navigate to the OrderFragment.
TextView and set its id to order_text and its text to This is the Order Fragment.FirstFragment to OrderFragment. Click the Code tab and you will see that the following action has been added:<action
android:id="@+id/action_FirstFragment_to_orderFragment"
app:destination="@id/orderFragment" />
onClick for the FloatingActionButton which will implement the navigation action from FirstFragment to OrderFragment:NavHostFragment.findNavController(FirstFragment.this)
.navigate(R.id.action_FirstFragment_to_orderFragment, null);
FloatingActionButton takes you to the OrderFragment and the back button takes you back to the Firstfragment.We will now change the Icon for the FloatingActionButton (FAB) to be the shopping cart icon that we added to the drawable folder earlier. The initial icon for the FAB is set in activity_main.xml. If you open that file you will see the following code to define the FAB:
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
app:srcCompat="@android:drawable/ic_dialog_email" />
The last line contains a link to the drawable resource for the email icon. As our FirstFragment now has control of the FAB, we will make that fragment change the icon.
fab:fab.setImageResource(R.drawable.ic_shopping_cart);
OrderFragment.The solution code for this task is included in the code and layout for Android Studio project DroidCafe.
Challenge: The DroidCafe app's FirstFragment links to a second Fragment called OrderFragment. You learned in another lesson (Codelab 2.4: Jetpack navigation - step 8 Safe Args) how to send data from a Fragment to another Fragment. Change the app to send the order message for the selected dessert in FirstFragment to a new TextView at the top of the OrderFragment layout.
MainActivityprivate AppBarConfiguration appBarConfiguration;
NavHostFragment host = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
NavController navController = host.getNavController();
appBarConfiguration = new AppBarConfiguration.Builder(navController.getGraph()).build();
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
@Override
public boolean onSupportNavigateUp() {
return NavigationUI.navigateUp(Navigation.findNavController(this, R.id.nav_host_fragment), appBarConfiguration)
|| super.onSupportNavigateUp();
}
dependencies {
classpath 'com.android.tools.build:gradle:4.0.2'
def nav_version = "2.3.0"
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
}
apply plugin: 'com.android.application'
apply plugin: "androidx.navigation.safeargs"
Java (Generated) folder with two sub-folders, one containing the FirstFragmentDirectionsmOrderMessage) in FirstFragment for the order message that appears in the Toast.mOrderMessage to be an empty String in the onCreateView of FirstFragment.showDonutOrder(), showIceCreamOrder(), and showFroyoOrder() click handlers to assign the message string mOrderMessage before displaying the Toast. For example, the following assigns the donut_order_message string to mOrderMessage and displays the Toast:mOrderMessage = getString(R.string.donut_order_message);
displayToast(mOrderMessage);
OrderFragment and then click the + symbol next to Arguments in the Attributes panelorder_text, the Type to be String, and the Default Value to be No selection made.FirstFragment to OrderFragment and change its id to place_order.java (Generated) contains a new class called OrderFragmentArgs.onClick() method of the FAB in FirstFragment to set the parameter value before navigating to OrderFragment:private String receivedOrderMessage;
receivedOrderMessage:View v = inflater.inflate(R.layout.fragment_order, container, false);
TextView textView = v.findViewById(R.id.order_text);
textView.setText(receivedOrderMessage);
return v;

The challenge solution code can be found on Blackboard.
ImageView to use it by dragging an ImageView to the layout and choosing the image for it.android:onClick attribute to make an ImageView clickable like a button. Specify the name of the click handler and in the MainActivity, create a click handler in the Activity to perform the action.Fragment's onViewCreated method to use view.findViewById to return the ImageView object and then use the setOnclickListener to add a listener for the click events.Fragment destination: In res > navigation > nav_graph.xml, click the Add Destination iconToast message from a Fragment:Toast.makeText(getActivity().getApplicationContext(), message,
Toast.LENGTH_SHORT).show();
The related concept documentation is in 4.1: Buttons and clickable images.