The user interface (UI) that appears on a screen of an Android 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, and the base class for classes that provide
interactive UI components such as buttons, checkboxes, and text entry
fields. Commonly used View subclasses described over several lessons
include:
View
elements and positioning them.The Java code that displays and drives the UI is contained in a class that extends Activity. An Activity
is usually associated with a layout of UI views defined as an XML (eXtended Markup Language) file. This XML file is usually named after its Activity and defines the layout of View elements on the screen.
For example, the MainActivity code in the Hello World app displays a layout defined in the activity_main.xml layout file, which includes a TextView with the text "Hello World".
In more complex apps, an Activity might implement actions to respond to user taps, draw graphical content, or request data from a database or the internet. You learn more about the Activity class in another lesson.
In this practical you learn how to create your first interactive app—an app that enables user interaction. You create an app using the Empty Activity template. You also learn how to use the layout editor to design a layout, and how to edit the layout in XML. You need to develop these skills so you can complete the other practicals in this course.
You should be familiar with:
The HelloToast app consists of two Button
elements and one TextView
. When the user taps the first Button
, it displays a short message (a Toast) on the screen. Tapping the second Button
increases a "click" counter displayed in the TextView
, which starts at zero.
Here's what the finished app looks like:
In this practical, you design and implement a project for the HelloToast app. A link to the solution code is provided at the end.
Attribute | Value |
Template | Empty Activity (Click Next) |
Application Name | Hello Toast |
Package Name | uk.aston.hellotoast (or your own domain) |
Language | Java |
Minimum SDK | API18: Android 4.3 (Jelly Bean) |
Android Studio provides the layout editor for quickly building an app's layout of user interface (UI) elements. It lets you drag elements to a visual design and blueprint view, position them in the layout, add constraints, and set attributes. Constraints determine the position of a UI element within the layout. A constraint represents a connection or alignment to another view, the parent layout, or an invisible guideline.
Explore the layout editor, and refer to the figure below as you follow the numbered steps:
View
elements are organized into a tree hierarchy of parents and children, in which a child inherits the attributes of its parent. In the figure above, the TextView
is a child of the ConstraintLayout. You will learn about these elements later in this lesson.TextView
that displays "Hello World".Tip: See Building a UI with Layout Editor for details on using the layout editor, and Meet Android Studio for the full Android Studio documentation.
In this task you create the UI layout for the HelloToast app in the layout editor using the ConstraintLayout features. You can create the constraints manually, as shown later, or automatically using the Autoconnect tool.
Follow these steps:
activity_main.xml
from the Project > Android pane if it is not already open. If the Design tab is not already selected, click it.TextView
is highlighted in the design and blueprint panes and the constraints for the element are visible.TextView
to delete the horizontal constraint that binds the view to the right side of the layout. The TextView
jumps to the left side because it is no longer constrained to the right side. To add back the horizontal constraint, click the same handle and drag a line to the right side of the layout.In the blueprint or design panes, the following handles appear on the TextView
element:
When enabled, the Autoconnect tool automatically creates two or more constraints for a UI element to the parent layout. After you drag the element to the layout, it creates constraints based on the element's position.
Follow these steps to add a Button
:
TextView
element is not needed, so while it is still selected, press the Delete key or choose Edit > Delete. You now have a completely blank layout.Button
in the top middle area of the layout, constraints may automatically appear. If not, you can drag constraints to the top, left side, and right side of the layout as shown in the animated figure below.You can remove constraints from an element by selecting the element and hovering your pointer over it to show the Clear Constraints button. Click this button to remove all constraints on the selected element. To clear a single constraint, click the specific handle that sets the constraint.
To clear all constraints in the entire layout, click the Clear All Constraints tool in the toolbar. This tool is useful if you want to redo all the constraints in your layout.
The Attributes pane offers access to all of the XML attributes you can assign to a UI element. You can find the attributes (known as properties) common to all views in the View class documentation.
In this task you enter new values and change values for important Button
attributes, which are applicable to most View
types.
The layout editor offers resizing handles on all four corners of a View
so you can resize the View
quickly. You can drag the handles on each corner of the View
to resize it, but doing so hardcodes the width and height dimensions. Avoid hardcoding sizes for most View
elements, because hardcoded dimensions can't adapt to different content and screen sizes.
Instead, use the Attributes pane on the right side of the layout editor to select a sizing mode that doesn't use hardcoded dimensions. The Attributes pane includes a square sizing panel called the view inspector at the top. The symbols inside the square represent the height and width settings as follows:
In the figure above:
layout_height
attribute and appears in two segments on the top and bottom sides of the square. The angles indicate that this control is set to wrap_content
, which means the View
will expand vertically as needed to fit its contents. The "0" indicates a standard margin set to 0dp.layout_width
and appears in two segments on the left and right sides of the square. The angles indicate that this control is set to wrap_content
, which means the View
will expand horizontally as needed to fit its contents, up to a margin of 0dp.Follow these steps:
Button
in the Component Tree pane.layout_width
attribute in the Attributes pane shows the value match_constraint
and the Button
element stretches horizontally to fill the space between the left and right sides of the layout.Button
, and make the same changes to the layout_width
as in the previous step, as shown in the figure below.As shown in the previous steps, the layout_width
and layout_height
attributes in the Attributes pane change as you change the height and width controls in the inspector. These attributes can take one of three values for the layout, which is a ConstraintLayout
:
match_constraint
setting expands the View
element to fill its parent by width or height—up to a margin, if one is set. The parent in this case is the ConstraintLayout
. You learn more about ConstraintLayout
in the next task.wrap_content
setting shrinks the View
element's dimensions so it is just big enough to enclose its content. If there is no content, the View
element becomes invisible.dp
units). For example, 16dp
means 16 density-independent pixels.Tip: If you change the layout_width
attribute using its popup menu, the layout_width
attribute is set to zero because there is no set dimension. This setting is the same as match_constraint
- the view can expand as much as possible to meet constraints and margin settings.
To identify each View
uniquely within an Activity
layout, each View
or View
subclass (such as Button
) needs a unique ID. And to be of any use, the Button
elements need text. View
elements can also have backgrounds that can be colors or images.
The Attributes pane offers access to all of the attributes you can assign to a View
element. You can enter values for each attribute, such as the android:id
, background
, textColor
, and text
attributes.
The following animated figure demonstrates how to perform these steps:
Button
, edit the ID field at the top of the Attributes pane to button_toast for the android:id
attribute, which is used to identify the element in the layout.background
attribute to @color/colorPrimary. (As you enter @c, choices appear for easy selection.)textColor
attribute to @android:color/white.text
attribute to Toast.Button
, using button_count as the ID, Count for the text
attribute, and the same colors for the background and text as the previous steps.The colorPrimary
is the primary color of the theme, one of the predefined theme base colors defined in the colors.xml
resource file. It is used for the app bar. Using the base colors for other UI elements creates a uniform UI. You will learn more about app themes and Material Design in another lesson.
One of the benefits of ConstraintLayout is the ability to align or otherwise constrain elements relative to other elements. In this task you will add a TextView
in the middle of the layout, and constrain it horizontally to the margins and vertically to the two Button
elements. You will then change the attributes for the TextView
in the Attributes pane.
TextView
from the Palette pane to the upper part of the layout, and drag a constraint from the top of the TextView
to the handle on the bottom of the ToastButton
. This constrains the TextView
to be underneath the Button
.TextView
to the handle on the top of the CountButton
, and from the sides of the TextView
to the sides of the layout. This constrains the TextView
to be in the middle of the layout between the two Button
elements.With the TextView
selected, open the Attributes pane, if it is not already open. Set attributes for the TextView
as shown in the animated figure below. The attributes you haven't encountered yet are explained after the figure:
ID
to show_count.text
to 0.textAppearance
and set the textSize
to 160sp.textStyle
to B (bold) and the textAlignment
to ALIGNCENTER (center the paragraph).layout_width
and layout_height
) to match_constraint.textColor
to @color/colorPrimary.background
, and then enter #FFFF00 for a shade of yellow.gravity
, expand gravity
, and select center_vertical (for center-vertical).TextView
a margin of 8 all aroundtextSize
: The text size of the TextView
. For this lesson, the size is set to 160sp
. The sp
stands for scale-independent pixel, and like dp
, is a unit that scales with the screen density and user's font size preference. Use dp units when you specify font sizes so that the sizes are adjusted for both the screen density and the user's preference.textStyle
and textAlignment
: The text style, set to B (bold) in this lesson, and the text alignment, set to ALIGNCENTER
(center the paragraph).gravity
: The gravity
attribute specifies how a View
is aligned within its parent View
or ViewGroup
. In this step, you center the TextView
to be centered vertically within the parent ConstraintLayout
.You may notice that the background
attribute is on the first page of the Attributes pane for a Button
, but on the second page of the Attributes pane for a TextView
. The Attributes pane changes for each type of View
. The most popular attributes for the View
type appear on the first page, and the rest are listed on the second page.
The Hello Toast app layout is nearly finished! However, an exclamation point appears next to each UI element in the Component Tree. Right click on one of these exclamation points to view warnings pane, as shown below. The same warning appears for all three elements: hardcoded strings should use resources.
The easiest way to fix layout problems is to edit the layout in XML. While the layout editor is a powerful tool, some changes are easier to make directly in the XML source code.
For this task, open the activity_main.xml
file if it is not already open, and click the Code tab at the top right of the layout editor.
The XML editor appears, replacing the design and blueprint panes. As you can see in the figure below, which shows part of the XML code for the layout, the warnings are highlighted—the hardcoded strings "Toast"
and "Count"
. (The hardcoded "0"
is also highlighted but not shown in the figure.) Hover your pointer over the hardcoded string "Toast"
to see the warning message.
Instead of hard-coding strings, it is a best practice to use string resources, which represent the strings. Having the strings in a separate file makes it easier to manage them, especially if you use these strings more than once. Also, string resources are mandatory for translating and localizing your app, because you need to create a string resource file for each language.
"Toast"
(the first highlighted warning).values/res/string.xml
file, and the string in your code is replaced with a reference to the resource: @string/button_label_toast
button_label_count
for "Count"
, and count_initial_value
for "0"
.strings.xml
file:<resources>
<string name="app_name">HelloToast</string>
<string name="button_label_toast">Toast</string>
<string name="button_label_count">Count</string>
<string name="count_initial_value">0</string>
</resources>
strings.xml
file another string resource named toast_message
for the phrase "Hello Toast!"
:<resources>
<string name="app_name">HelloToast</string>
<string name="button_label_toast">Toast</string>
<string name="button_label_count">Count</string>
<string name="count_initial_value">0</string>
<string name="toast_message">Hello Toast!</string>
</resources>
Tip: The string resources include the app name, which appears in the app bar at the top of the screen if you start your app project using the Empty Template. You can change the app name by editing the app_name
resource.
In this task, you add a Java method for each Button
in MainActivity
that executes when the user taps the Button.
onClick
attribute and handler to each ButtonA click handler is a method that is invoked when the user clicks or taps on a clickable UI element. In Android Studio you can specify the name of the method in the onClick
field in the Design tab's Attributes pane. You can also specify the name of the handler method in the XML editor by adding the android:onClick
property to the Button
. You will use the latter method because you haven't yet created the handler methods, and the XML editor provides an automatic way to create those methods.
Button
with the android:id
set to button_toast
:<Button
android:id="@+id/button_toast"
android:layout_width="0dp"
...
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
android:onClick
attribute to the end of the button_toast
element after the last attribute and before the />
end indicator:<Button
android:id="@+id/button_toast"
...
app:layout_constraintTop_toTopOf="parent"
android:onClick="showToast" />
MainActivity
class will be opened in the editor with a new method called showToast
."showToast"
). Press Alt-Enter (Option-Enter on the Mac), select Create ‘showToast(view)' in ‘MainActivity', and click OK.button_countButton
: Add the android:onClick
attribute to the end, and add the click handler:<Button
android:id="@+id/button_count"
...
app:layout_constraintStart_toStartOf="parent"
android:onClick="countUp" />
The XML code for the UI elements within activity_main.xml
now looks like this:<?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=".MainActivity">
<Button
android:id="@+id/button_toast"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:background="@color/colorPrimary"
android:text="@string/button_label_toast"
android:textColor="@android:color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:onClick="showToast" />
<Button
android:id="@+id/button_count"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:background="@color/colorPrimary"
android:text="@string/button_label_count"
android:textColor="@android:color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:onClick="countUp" />
<TextView
android:id="@+id/show_count"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:background="#FFFF00"
android:gravity="center_vertical"
android:text="@string/count_initial_value"
android:textAlignment="center"
android:textColor="@color/colorPrimary"
android:textSize="160sp"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@+id/button_count"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button_toast" />
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.java
is not already open, expand java in the Project > Android view, expand uk.aston.hellotoast
, and then double-click MainActivity. The code editor appears with the code in MainActivity
:package uk.aston.hellotoast;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void showToast(View view) {
}
public void countUp(View view) {
}
}
You will now edit the showToast()
method—the ToastButton
click handler in MainActivity
- so that it shows a message. A Toast provides a way to show a simple message in a small popup window. It fills only the amount of space required for the message. The current activity remains visible and interactive. A Toast
can be useful for testing interactivity in your app - add a Toast
message to show the result of tapping a Button
or performing an action.
Follow these steps to edit the ToastButton
click handler:
Locate the newly created showToast()
method.
public void showToast(View view) {
}
Toast
, call the makeText() factory method on the Toast class.public void showToast(View view) {
Toast toast = Toast.makeText(
}
Activity
. Because a Toast
displays on top of the Activity
UI, the system needs information about the current Activity
. When you are already within the context of the Activity
whose context you need, use this
as a shortcut.Toast toast = Toast.makeText(this,
toast_message
you created in a previous step). The string resource toast_message
is identified by R.string
.Toast toast = Toast.makeText(this, R.string.toast_message,
Toast toast = Toast.makeText(this, R.string.toast_message,
Toast.LENGTH_SHORT);
The duration of a Toast
display can be either Toast.LENGTH_LONG
or Toast.LENGTH_SHORT
. The actual lengths are about 3.5 seconds for the long Toast
and 2 seconds for the short Toast
.Toast
by calling show()
. The following is the entire showToast()
method:public void showToast(View view) {
Toast toast = Toast.makeText(this, R.string.toast_message,
Toast.LENGTH_SHORT);
toast.show();
}
Run the app and verify that the Toast
message appears when the Toast button is tapped.
You will now edit the countUp()
method—the CountButton
click handler in MainActivity
- so that it displays the current count after Count is tapped. Each tap increases the count by one.
The code for the handler must:
TextView
to display it.Follow these steps to edit the CountButton
click handler:
countUp()
method.public void countUp(View view) {
}
public void countUp(View view) {
mCount++;
}
If the red bulb icon doesn't appear, click the mCount++
expression. The red bulb eventually appears.int
). If you press Enter to accept the int
type, that will complete the operation. Watch this animated image to see it done:onCreate()
method in MainActivity
and add a line to initialise the private member variable to zero:@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mCount = 0;
}
mCount
variable on the screen of our app using the TextView
whose ID we set to be show_count
. You need to get a reference to the TextView
using the ID you set in the layout file. In order to get this reference only once, specify it in the onCreate()
method. As you learn in another lesson, the onCreate()
method is used to inflate the layout, which means to set the content view of the screen to the XML layout. You can also use it to get references to other UI elements in the layout, such as the TextView
.findViewById
to the end of your onCreate
method to find and return the TextView
which has the ID value show_count
:@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mCount = 0;
mShowCount = (TextView) findViewById(R.id.show_count);
}
A View
, like a string, is a resource that can have an id. The findViewById call takes the ID of a view as its parameter and returns the View
. Because the method returns a View
, you have to cast the result to the view type you expect, in this case (TextView
).TextView
. You should now have two member variables in MainActivity
:private int mCount;
private TextView mShowCount;
TextView
to mShowCount
, you can use mShowCount
to set the text in the TextView
to the value of the mCount
variable. Add the following code to the countUp()
method:if (mShowCount != null) {
mShowCount.setText(Integer.toString(mCount));
}
The entire countUp()
method now looks like this:public void countUp(View view) {
mCount++;
if (mShowCount != null) {
mShowCount.setText(Integer.toString(mCount));
}
}
Tip: For an in-depth tutorial on using ConstraintLayout
, see the Codelab entitled Using ConstraintLayout to design your views.
You can find a ZIP of the Android Studio project: HelloToast
on Blackboard.
The HelloToast
app looks fine when the device or emulator is vertically oriented. However, if you switch the device or emulator to horizontal orientation, the CountButton
may overlap the TextView
along the bottom depending on the screen resolution of the emulated device. Watch the animated image below to see what happens when we run the app on a Nexus One and configure the emulator to rotate the screen when the orientation changes from portrait to landscape and vice versa:
Challenge: Change the layout so that it looks good in both horizontal and vertical orientations:
If you copy a project and want to work on the copy, you should rename and refactor the copy. In the following steps we are going to do that for the HelloToast project. Here are the steps to refactor the project:
HelloToast
folder to a new location and rename it HelloToastChallengeuk.aston.hellotoast
and select Refactor > Rename. A Warning dialog is displayed. Select Rename package.hellotoastchallenge
.strings.xml
file.app_name
string value to HelloToastChallenge
.AndroidManifest.xml
and ensure that the package name has been refactored. The opening element should look like this:<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="uk.aston.hellotoastchallenge">
build.gradle(Module: app)
and ensure that the applicatioId
has been renamed:defaultConfig {
applicationId "uk.aston.hellotoastchallenge"
settings.gradle(Project Settings)
and ensure that the rootProject.name
has been updated. That file should look like this:include ':app'
rootProject.name = "HelloToastChallenge"
After you change the value of rootProject.name
, click Sync now which should appear at the top right hand corner of the Android Studio editor window.Here is an animate image of the above steps (if this image is too small, try right clicking the image and choose Open image in new tab):
Button
and CountButton
appear on the left side, as shown in the figure below. The TextView
appears next to them, but only wide enough to show its contents. (Hint: Use layout_width
and layout_height
set to wrap_content
before you add the layout constraints. You can remove all the constraints by clicking View
, ViewGroup
, and layouts:
View
superclass.View
elements can be grouped inside a ViewGroup, which acts as a container. The relationship is parent-child, in which the parent is a ViewGroup
, and the child is a View
or another ViewGroup
.onCreate()
method is used to inflate the layout, which means to set the content view of the screen to the XML layout. You can also use it to get references to other UI elements in the layout.View
, like a string, is a resource that can have an id. The findViewById call takes the ID of a view as its parameter and returns the View
.Using the layout editor:
Setting layout width and height:
The layout_width
and layout_height
attributes change as you change the height and width size controls in the view inspector. These attributes can take one of three values for a ConstraintLayout
:
match_constraint
setting expands the view to fill its parent by width or height—up to a margin, if one is set.wrap_content
setting shrinks the view dimensions so the view is just big enough to enclose its content. If there is no content, the view becomes invisible.dp
(density-independent pixels) to specify a fixed size, adjusted for the screen size of the device.Extracting string resources:
Instead of hard-coding strings, it is a best practice to use string resources, which represent the strings. Follow these steps:
values/res/string.xml
file, and the string in your code is replaced with a reference to the resource: @string/button_label_toast
Handling clicks:
Button
by entering its name in the onClick
field in the Design tab's Attributes pane, or in the XML editor by adding the android:onClick
property to a UI element such as a Button
.Activity
using the View
parameter. Example: public void showToast(View view) {/...}
.Button
properties in the Button class documentation, and all the TextView
properties in the TextView class documentation.Displaying Toast messages:
Toast
, follow these steps:makeText()
factory method on the Toast
class.Activity
and the message to display (such as a string resource).Toast.LENGTH_SHORT
for a short period. The duration can be either Toast.LENGTH_LONG
or Toast.LENGTH_SHORT
.Toast
by calling show()
.The related concept documentation is in 1.2: Layouts and resources for the UI.