This practical codelab is part of Unit 1: of CS3040/DC3040. You will get the most value out of this course if you work through the codelabs in sequence:
For the complete list of codelabs in CS3040/DC3040, please see the Blackboard module.
For the Androidn training material this module is based on, including concept chapters, apps, and slides, see Android Developer Fundamentals (Version 2).
Note: This module uses the terms "codelab" and "practical" interchangeably.
As you learned in Unit 1.2 Part A: Your first interactive UI, you can build a user interface (UI) using ConstraintLayout in the layout editor, which places UI elements in a layout using constraint connections to other elements and to the layout edges. ConstraintLayout
was designed to make it easy to drag UI elements into the layout editor.
ConstraintLayout
is a ViewGroup, which is a special View
that can contain other View
objects (called children or child views). This practical shows more features of ConstraintLayout
and the layout editor.
This practical also introduces two other ViewGroup
subclasses:
LinearLayout: A group that aligns child View
elements within it horizontally or vertically.
RelativeLayout: A group of child View
elements in which each View
element is positioned and aligned relative to other View
element within the ViewGroup
. Positions of the child View
elements are described in relation to each other or to the parent ViewGroup
.
You should be able to:
ConstraintLayout
baseline constraints to align elements with text.ConstraintLayout
pack and align buttons to align elements.LinearLayout
.LinearLayout
.RelativeLayout
.The Hello Toast app in a previous lesson uses ConstraintLayout to arrange the UI elements in the Activity
layout, as shown in the figure below.
To gain more practice with ConstraintLayout
, you will create a variant of this layout for horizontal orientation as shown in the figure below.
You will also learn how to use baseline constraints and some of the alignment features of ConstraintLayout
by creating another layout variant for tablet displays.
You also learn about other ViewGroup
subclasses such as LinearLayout and RelativeLayout, and change the Hello Toast app layout to use them.
In the previous lesson, the coding challenge required changing the layout of the Hello Toast app so that it would fit properly in a horizontal or vertical orientation. In this task you will learn an easier way to create variants of your layout for horizontal (also known as landscape) and vertical (also known as portrait) orientations for phones, and for larger displays such as tablets.
In this task you will use some of the buttons in the top two toolbars of the layout editor. The top toolbar lets you configure the appearance of the layout preview in the layout editor:
In the figure above:
The second toolbar lets you configure the appearance of UI elements in a ConstraintLayout
, and to zoom and pan the preview:
In the figure above:
In the figure above:
Tip: To learn more about using the layout editor, see Build a UI with Layout Editor. To learn more about how to build a layout with ConstraintLayout
, see Build a Responsive UI with ConstraintLayout.
To preview the Hello Toast app layout with a horizontal orientation, follow these steps:
The visual difference between vertical and horizontal orientations for this layout is that the digit (0
) in the show_countTextView
element is too low for the horizontal orientation—too close to the Countbutton
. Depending on which device or emulator you use, the TextView
element may appear too large or not centered because the text size is fixed to 160sp
.
To fix this for horizontal orientations while leaving vertical orientations alone, you can create variant of the Hello Toast app layout that is different for a horizontal orientation. Follow these steps:
activity_main.xml (land)
.You can preview the layout for different devices without having to run the app on the device or emulator. Follow these steps:
TextView
.You can use the Attributes pane in the Design tab to set or change attributes, but it can sometimes be quicker to use the Code tab to edit the XML code directly. The Split tab shows the XML code and provides a Preview tab on the right side of the window to show the layout preview, as shown in the figure below.
The figure above shows the following:
You can try using the Device for Preview option to select different devices. I found that none of the pre-defined phone options gave a particularly bad layout, however if I install the app on my Samsung S5, the bottom of the zero character is off the screen in landscape mode. Even worse, if you choose a wearable option using Device for Preview, the Wear Square optiondoes not show any of the zero character.
To change the layout, follow these steps:
TextView
element in the XML code.android:textSize="160sp"
attribute to android:textSize="120sp"
. We don't need the app to display correctly on a wearable device, but if you have a phone with a small screen you want to choose the android:textSize
value to be one that works with your device. You might need a smaller value that 120sp
.android:textSize
.As you learned previously, you can preview the layout for different devices by clicking the Device in Editor button in the top toolbar. If you pick a device such as Nexus 10 (a tablet) from the menu, you can see that the layout is not ideal for a tablet screen—the text of each Button
is too small, and the arrangement of the Button
elements at the top and bottom is not ideal for a large-screen tablet.
To fix this for tablets while leaving the phone-size horizontal and vertical orientations alone, you can create variant of the layout that is completely different for tablets. Follow these steps:
A new editor window opens with the sw600dp/activity_main.xml tab showing the layout for a tablet-sized device. The editor also picks a tablet device, such as the Nexus 9 or Nexus 10, for the preview. You can change this layout, which is specifically for tablets, without changing the other layouts.
You can use the Attributes pane in the Design tab to change attributes for this layout.
TextView
called show_count
. To get the TextView
out of the way so that you can freely drag the Button
elements, drag a corner of it to resize it, as shown in the animated figure below.button_toastButton
in the Component Tree, click the Attributes tab to open the Attributes pane, and change the textSize
to 60sp (#1 in the figure below) and the layout_width
to wrap_content
(#2 in the figure below).wrap_content
from the layout_width
menu.wrap_content
so that if the Button
text is localized into a different language, the Button
will appear wider or thinner to accommodate the word in the different language.button_countButton
in the Component Tree
, change the textSize
to 60sp and the layout_width
to wrap_content
, and drag the Button
above the TextView
to an empty space in the layout.You can align one UI element that contains text, such as a TextView
or Button
, with another UI element that contains text. A baseline constraint lets you constrain the elements so that the text baselines match.
button_toastButton
to the top and left side of the layout, drag the button_countButton
to a space near the button_toastButton
, and constrain the button_countButton
to the right side of the button_toastButton
, and assign borders of 8 around them, as shown in the animated figure:button_countButton
so that its text baseline matches the text baseline of the button_toastButton
. Right-click the button_count
element, and choose Show Baseline from the menu.button_countButton
and drag a baseline constraint line to the baseline of the button_toast
element as shown below:A chain is a group of views that are linked to each other with bi-directional position constraints. The views within a chain can be distributed either vertically or horizontally. You can read more about chains. We will create a chain containing the two buttons and then expand the buttons to fill the layout horizontally. The animated image below illustrates the steps.
Button
with id button_toast
and set its layout_width
to 0dp (Match Constraints).Button
with id button_count
and set its layout_width
to 0dp (Match Constraints).show_countTextView
to the bottom of the button_toastButton
and to the sides and bottom of the layout, set its layout_width
and layout_height
to Match Constraints and set its margins to 8, as shown in the animated figure below.Tip: For more information on using ConstraintLayout
, see Build a Responsive UI with ConstraintLayout.
You can find the completed code for this part of this codelab on Blackboard.
Challenge: Explore the different options for Horizontal Chain Style (right-click the chain of buttons and select Chains > Horizontal Chain Style. This option goes hand in hand with the layout_width
of each Button
.
Try and create the following set of variations of the button layouts, the first of which we already did in the exercise above.
Hint: You only need to change the settings for layout_width
and chain style.
LinearLayout is a ViewGroup
that arranges its collection of views in a horizontal or vertical row. A LinearLayout
is one of the most common layouts because it is simple and fast. It is often used within another view group to arrange UI elements horizontally or vertically.
A LinearLayout
is required to have these attributes:
layout_width
layout_height
orientation
The layout_width
and layout_height
can take one of these values:
match_parent
: Expands the view to fill its parent by width or height. When the LinearLayout is the root view, it expands to the size of the screen (the parent view).wrap_content
: 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): Specify a fixed size, adjusted for the screen density of the device. For example, 16dp
means 16 density-independent pixels.orientation
can be:horizontal
: Views are arranged from left to right.vertical
: Views are arranged from top to bottom.In this task you will change the ConstraintLayout
root view group for the Hello Toast app to LinearLayout
so that you can gain practice in using LinearLayout
.
activity_main.xml
layout file (if it is not already open), and click the Code tab at the top right of the editing pane to see the XML code. At the very top of the XML code is the following tag line:<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">
androidx.constraintlayout.widget.ConstraintLayout
tag name to be LinearLayout
so that the code looks like this:<LinearLayout
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">
</LinearLayout>
(Android Studio automatically changes the closing tag if you change the opening tag). If it hasn't changed automatically, change it manually.<LinearLayout
tag line, add the following attribute after the android:layout_height
attribute:android:orientation="vertical"
ConstraintLayout
and are not relevant for LinearLayout
.Follow these steps to change UI element attributes so that they work with LinearLayout
:
activity_main.xml
layout file (if it is not already open), and click the Code tab to view the XML.button_toastButton
element, and change the following attribute:Original | Change to |
|
|
button_toast
element:app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
button_count
Button element, and change the following attribute:Original | Change to |
|
|
button_count
element:app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
TextView
element show_count
called , and change the following attributes:Original | Change to |
|
|
|
|
show_count
element:app:layout_constraintBottom_toTopOf="@+id/button_count"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button_toast"
Click the Design tab on the top right of the editor window to see a preview of the layout thus far:LinearLayout arranges its elements in a horizontal or vertical row. You have already added the android:orientation="vertical"
attribute for the LinearLayout
, so the elements are stacked on top of each other vertically as shown in the previous figure.
To change their positions so that the Count button is on the bottom, follow these steps:
activity_main.xml
layout file and click the Code tab to view the XML.button_count
Button and all of its attributes, from the <Button
tag up to and including the closing />
tag, and choose Edit > Cut./>
tag of the TextView
element but before the closing </LinearLayout>
tag, and choose Edit > Paste.<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/button_toast"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:background="@color/colorPrimary"
android:onClick="showToast"
android:text="@string/button_label_toast"
android:textColor="@android:color/white" />
<TextView
android:id="@+id/show_count"
android:layout_width="match_parent"
android:layout_height="wrap_content"
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="240sp"
android:textStyle="bold" />
<Button
android:id="@+id/button_count"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:background="@color/colorPrimary"
android:onClick="countUp"
android:text="@string/button_label_count"
android:textColor="@android:color/white" />
</LinearLayout>
By moving the button_countButton
below the TextView
, the layout is now close to what you had before, with the Countbutton
on the bottom. The preview of the layout now looks like the following:
Specifying gravity
and weight
attributes gives you additional control over arranging views and content in a LinearLayout
.
The android:gravity
attribute specifies the alignment of the content of a View
within the View
itself. In the previous lesson you set this attribute for the show_countTextView
in order to center the content (the digit 0) in the middle of the TextView
:
android:gravity="center_vertical"
The android:layout_weight
attribute indicates how much of the extra space in the LinearLayout
will be allocated to the View
. If only one View
has this attribute, it gets all the extra screen space. For multiple View
elements, the space is prorated. For example, if the Button
elements each have a weight of 1 and the TextView
2, totaling 4, the Button
elements get one quarter of the space each, and the TextView gets the remaining half.
On different devices, the layout may show the show_countTextView
element as filling part or most of the space between the Toast and Count buttons. In order to expand the TextView
to fill the available space no matter which device is used, specify the android:gravity
attribute for the TextView
. Follow these steps:
activity_main.xml
layout file, and click the Code tab to view the XML.show_countTextView
element, and add the following attribute:android:layout_weight="1"
The show_countTextView
element takes up all the space between the buttons. You can preview the layout for different devices, as you did in a previous task by clicking the Device in Editor button as you did in a previous task by clicking the Device in Editor button in the top toolbar of the preview pane, and choosing a different device. No matter which device you choose for the preview, the
show_countTextView
element should take up all the space between the buttons.
The XML code in activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/button_toast"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:background="@color/colorPrimary"
android:onClick="showToast"
android:text="@string/button_label_toast"
android:textColor="@android:color/white" />
<TextView
android:id="@+id/show_count"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:background="#FFFF00"
android:gravity="center_vertical"
android:layout_weight="1"
android:text="@string/count_initial_value"
android:textAlignment="center"
android:textColor="@color/colorPrimary"
android:textSize="240sp"
android:textStyle="bold" />
<Button
android:id="@+id/button_count"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:background="@color/colorPrimary"
android:onClick="countUp"
android:text="@string/button_label_count"
android:textColor="@android:color/white" />
</LinearLayout>
A RelativeLayout is a view grouping in which each view is positioned and aligned relative to other views within the group. In this task you will learn how to build a layout with RelativeLayout
.
An easy way to change the LinearLayout
to a RelativeLayout
is to add XML attributes in the Text tab.
activity_main.xml
layout file, and click the Code tab at the top right of the editing pane to see the XML code.<LinearLayout
at the top to <RelativeLayout
so that the statement looks like this:<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
</LinearLayout>
has automatically been changed to </RelativeLayout>
and if it hasn't, change it manually.An easy way to rearrange and position views in a RelativeLayout is to add XML attributes in the Text tab.
Button
(button_count
) overlays the ToastButton
, which is why you can't see the ToastButton
(button_toast
).TextView
(show_count
) overlays the Button
elements.android:layout_below
attribute to the button_count
Button to position the Button
directly below the show_count
TextView. This attribute is one of several attributes for positioning views within a RelativeLayout
- you place views in relation to other views.android:layout_below="@+id/show_count"
android:layout_centerHorizontal
attribute to the same Button
to center the view horizontally within its parent, which in this case is the RelativeLayout
view group.android:layout_centerHorizontal="true"
The full XML code for the button_count
Button is as follows: <Button
android:id="@+id/button_count"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/show_count"
android:layout_centerHorizontal="true"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:background="@color/colorPrimary"
android:onClick="countUp"
android:text="@string/button_label_count"
android:textColor="@android:color/white" />
show_count
TextView:android:layout_below="@+id/button_toast"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
The android:layout_alignParentLeft
attribute aligns the view to the left side of the RelativeLayout
parent view group. While this attribute by itself is enough to align the view to the left side, you may want the view to align to the right side if the app is running on a device that is using a right-to-left language. Thus, the android:layout_alignParentStart
attribute makes the "start" edge of this view match the start edge of the parent. The start is the left edge of the screen if the preference is left-to-right, or it is the right edge of the screen if the preference is right-to-left.android:layout_weight="1"
attribute from the show_count
TextView, which is not relevant for a RelativeLayout
. The layout preview now looks like the following figure:RelativeLayout
makes it relatively easy to quickly place UI elements in a layout. To learn more about how to position views in a RelativeLayout
, see "Positioning Views" in the "Relative Layout" topic of the API Guide.The XML code in activity_main.xml
:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/button_toast"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:background="@color/colorPrimary"
android:onClick="showToast"
android:text="@string/button_label_toast"
android:textColor="@android:color/white" />
<TextView
android:id="@+id/show_count"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/button_toast"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:layout_weight="1"
android:background="#FFFF00"
android:gravity="center_vertical"
android:text="@string/count_initial_value"
android:textAlignment="center"
android:textColor="@color/colorPrimary"
android:textSize="240sp"
android:textStyle="bold" />
<Button
android:id="@+id/button_count"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/show_count"
android:layout_centerHorizontal="true"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:background="@color/colorPrimary"
android:onClick="countUp"
android:text="@string/button_label_count"
android:textColor="@android:color/white" />
</RelativeLayout>
Using the layout editor to preview and create variants:
land/activity_main.xml
tab showing the layout for the landscape (horizontal) orientation.Using ConstraintLayout
:
ConstraintLayout
root, click the Clear All ConstraintsTextView
or Button
, with another UI element that contains text. A baseline constraint lets you constrain the elements so that the text baselines match.layout_width
/layout_height
of each view.Using LinearLayout
:
LinearLayout
is required to have the layout_width
, layout_height
, and orientation
attributes.match_parent
for layout_width
or layout_height
: Expands the View
to fill its parent by width or height. When the LinearLayout
is the root View
, it expands to the size of the screen (the parent View
).wrap_content
for layout_width
or layout_height
: Shrinks the 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) for layout_width
or layout_height
: Specify a fixed size, adjusted for the screen density of the device. For example, 16dp means 16 density-independent pixels.orientation
for a LinearLayout
can be horizontal
to arrange elements from left to right, or vertical
to arrange elements from top to bottom.gravity
and weight
attributes gives you additional control over arranging views and content in a LinearLayout
.android:gravity
attribute specifies the alignment of the content of a View
within the View
itself.android:layout_weight
attribute indicates how much of the extra space in the LinearLayout
will be allocated to the View
. If only one View
has this attribute, it gets all the extra screen space. For multiple View
elements, the space is prorated. For example, if two Button
elements each have a weight of 1 and a TextView
2, totaling 4, the Button
elements get one quarter of the space each, and the TextView
gets half.Using RelativeLayout
:
ViewGroup
in which each view is positioned and aligned relative to other views within the group.android:layout_alignParentTop
to align the View
to the top of the parent.android:layout_alignParentLeft
to align the View
to the left side of the parent.android:layout_alignParentStart
to make the start edge of the View
match the start edge of the parent. This attribute is useful if you want your app to work on devices that use different language or locale preferences. The start is the left edge of the screen if the preference is left-to-right, or it is the right edge of the screen if the preference is right-to-left.The related concept documentation is in 1.2: Layouts and resources for the UI.
Android Studio documentation:
Android developer documentation:
Other:
ConstraintLayout
to design your Android views