1. Before you begin
In this codelab, you will be building the layout for a basic tip calculator app. At the end of the codelab, you'll have a working UI for the app, but the app won't actually calculate the tip yet. Making the app work and look more professional will be in the following codelabs.
Prerequisites
- Able to create and run an Android app from a template in Android Studio
What you'll learn
- How to read and write XML layouts in Android
- How to build the layout for a simple form to take in user text input and choices
What you'll build
- The UI for a tip calculator Android app
What you need
- A computer with the latest stable version of Android Studio installed
- Internet connection to access the Android developer documentation
2. Start the project
Check out the tip calculator on Google: https://www.google.com/search?q=tip+calculator
In this pathway, you'll build a simple version of a tip calculator as an Android app.
Developers will often work in this way—getting a simple version of the app ready and partially functioning (even if it doesn't look very good), and then making it fully functional and visually polished later.
By the end of this codelab, your tip calculator app will look like this:
You will be using these UI elements that are provided by Android:
EditText
- for entering and editing textTextView
- to display text like the service question and tip amountRadioButton
- a selectable radio button for each tip optionRadioGroup
- to group the radio button optionsSwitch
- an on/off toggle for choosing whether to round up the tip or not
Create an Empty Activity project
- To start, create a new Kotlin project in Android Studio using the Empty Activity template.
- Call the app "Tip Time", with a minimum API level of 19 (KitKat). The package name is com.example.tiptime.
- Click Finish to create the app.
3. Read and understand XML
Instead of using the Layout Editor which you're already familiar with, you will build the layout of your application by modifying the XML that describes the UI. Learning how to understand and modify UI layouts using XML will be important for you as an Android developer.
You will be looking at, and editing the XML file that defines the UI layout for this app. XML stands for eXtensible Markup Language, which is a way of describing data using a text-based document. Because XML is extensible and very flexible, it's used for many different things, including defining the UI layout of Android apps. You may recall from earlier codelabs that other resources like strings for your app are also defined in an XML file called strings.xml
.
The UI for an Android app is built as a containment hierarchy of components (widgets), and the on-screen layouts of those components. Note those layouts are UI components themselves.
You describe the view hierarchy of UI elements on the screen. For example, a ConstraintLayout
(the parent) can contain Buttons
, TextViews
, ImageViews
, or other views (the children). Remember, ConstraintLayout
is a subclass of ViewGroup
. It allows you to position or size child views in a flexible manner.
Containment hierarchy of an Android app
Each UI element is represented by an XML element in the XML file. Each element starts and ends with a tag, and each tag starts with a <
and ends with a >
. Just as you can set attributes on UI elements using the Layout Editor (design), the XML elements can have attributes, too. Simplified, the XML for the UI elements above might be something like this:
<ConstraintLayout>
<TextView
text="Hello World!">
</TextView>
</ConstraintLayout>
Let's look at a real example.
- Open
activity_main.xml
(res > layout > activity_main.xml). - You might notice the app shows a
TextView
with "Hello World!" within aConstraintLayout
, as you have seen in previous projects created from this template.
- Find the options for Code, Split, and Design views in the upper right of the Layout Editor.
- Select the Code view.
This is what the XML in activity_main.xml
looks like:
<?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">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
There's a lot more going on than in the simplified example, but Android Studio does some things to help make the XML more readable, just as it does with your Kotlin code.
- Notice the indentation. Android Studio does this automatically to show you the hierarchy of elements. The
TextView
is indented because it is contained in theConstraintLayout
. TheConstraintLayout
is the parent, and theTextView
is the child. The attributes for each element are indented to show that they're part of that element. - Notice the color coding—some things are in blue, some in green, and so on. Similar parts of the file are drawn in the same color to help you match them up. In particular, notice that Android Studio draws the start and end of tags of elements in the same color. (Note: the colors used in the codelab may not match what you see in Android Studio.)
XML tags, elements and attributes
Here's a simplified version of the TextView
element so you can look at some of the important parts:
<TextView
android:text="Hello World!"
/>
The line with <TextView
is the start of the tag, and the line with />
is the end of the tag. The line with android:text="Hello World!"
is an attribute of the tag. It represents text that will be displayed by the TextView
. These 3 lines are a commonly used shorthand called an empty-element tag. It would mean the same thing if you wrote it with a separate start-tag and end-tag, like this:
<TextView
android:text="Hello World!"
></TextView>
It's also common with an empty-element tag to write it on as few lines as possible and combine the end of the tag with the line before it. So you might see an empty-element tag on two lines (or even one line if it had no attributes):
<!-- with attributes, two lines -->
<TextView
android:text="Hello World!" />
The ConstraintLayout
element is written with separate start and end tags, because it needs to be able to hold other elements inside it. Here's a simplified version of the ConstraintLayout
element with the TextView
element inside it:
<androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:text="Hello World!" />
</androidx.constraintlayout.widget.ConstraintLayout>
If you wanted to add another View
as a child of the ConstraintLayout
, like a Button
below the TextView
, it would go after the end of the TextView
tag />
and before the end tag of the ConstraintLayout
, like this:
<androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:text="Hello World!" />
<Button
android:text="Calculate" />
</androidx.constraintlayout.widget.ConstraintLayout>
More about XML for layouts
- Look at the tag for the
ConstraintLayout
, and notice that it saysandroidx.constraintlayout.widget.ConstraintLayout
instead of justConstraintLayout
like theTextView
. This is becauseConstraintLayout
is part of Android Jetpack, which contains libraries of code which offers additional functionality on top of the core Android platform. Jetpack has useful functionality you can take advantage of to make building apps easier. You'll recognize this UI component is part of Jetpack because it starts with "androidx". - You may have noticed the lines that begin with
xmlns:
, followed byandroid
,app
, andtools
.
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"
The xmlns
stands for XML namespace, and each line defines a schema, or vocabulary for attributes related to those words. The android:
namespace, for example, marks attributes that are defined by the Android system. All of the attributes in the layout XML begins with one of those namespaces.
- Whitespace between XML elements doesn't change the meaning to a computer, but it can help make the XML easier for people to read.
Android Studio will automatically add some whitespace and indenting for readability. You'll learn later how to have Android Studio make sure your XML follows coding style conventions.
- You can add comments to XML, just like you would with Kotlin code. Start
<!--
and end with-->
.
<!-- this is a comment in XML -->
<!-- this is a
multi-line
Comment.
And another
Multi-line comment -->
- Note the first line of the file:
<?xml version="1.0" encoding="utf-8"?>
This indicates that the file is an XML file, but not every XML file includes this.
4. Build the layout in XML
- Still in
activity_main.xml
, switch to the Split screen view to see the XML beside the Design Editor. The Design Editor allows you to preview your UI layout.
- It is up to personal preference which view you use, but for this codelab, use the Split view so you can see both the XML that you edit and the changes those edits make in the Design Editor.
- Try clicking on different lines, one below the
ConstraintLayout
, and then one below theTextView
, and notice that the corresponding view is selected in the Design Editor. The reverse works, too—for example, if you click on theTextView
in the Design Editor, the corresponding XML is highlighted.
Delete the TextView
- You don't need the
TextView
now, so delete it. Be sure to delete everything from the<TextView
to the closing/>
.
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
All that's left in the file is the ConstraintLayout
:
<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>
- Add 16dp of padding to the
ConstraintLayout
so the UI won't be crowded against the edge of the screen.
Padding is similar to margins, but it adds space to the inside of the ConstraintLayout
, instead of adding space to the outside.
<androidx.constraintlayout.widget.ConstraintLayout
...
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".MainActivity">
Add cost of service text field
In this step you'll add the UI element to allow the user to enter the cost of service into the app. You'll use an EditText
element, which lets a user enter or modify text in an app.
- Look at the
EditText
documentation, and examine the sample XML. - Find a blank space between the opening and closing tags of the
ConstraintLayout
. - Copy and paste the XML from the documentation into that space in your layout in Android Studio.
Your layout file should look 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"
android:padding="16dp"
tools:context=".MainActivity">
<EditText
android:id="@+id/plain_text_input"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:inputType="text"/>
</androidx.constraintlayout.widget.ConstraintLayout>
You may not understand all of this yet, but it will be explained in the following steps.
- Notice
EditText
is underlined in red. - Hover the pointer over it, and you'll see a "view is not constrained" error, which should look familiar from earlier codelabs. Recall that children of a
ConstraintLayout
need constraints so the layout knows how to arrange them.
- Add these constraints to the
EditText
to anchor it to the top left corner of the parent.
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
If you're writing in English or another language that's written left-to-right (LTR), the starting edge is the left. But some languages like Arabic are written right-to-left (RTL), so the starting edge is the right. That's why the constraint uses "start", so that it can work with either LTR or RTL languages. Similarly, constraints use "end" instead of right.
With the new constraints added, the EditText
element will look like this:
<EditText
android:id="@+id/plain_text_input"
android:layout_height="wrap_content"
android:layout_width="match_parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:inputType="text"/>
Review the EditText attributes
Double check all the EditText
attributes that you pasted in to make sure it works for how it will be used in your app.
- Find the
id
attribute, which is set to@+id/plain_text_input
. - Change the
id
attribute to a more appropriate name,@+id/cost_of_service
.
- Look at the
layout_height
attribute. It's set towrap_content
which means the height will be as tall as the content inside it. That's OK, because there will only be 1 line of text. - Look at the
layout_width
attribute. It's set tomatch_parent
, but you can't setmatch_parent
on a child ofConstraintLayout
. Furthermore, the text field doesn't need to be so wide. Set it to be a fixed width of160dp
, which should be plenty of space for the user to enter in a cost of service.
- Notice the
inputType
attribute—it's something new. The value of the attribute is"text"
, which means the user can type in any text characters into the field on screen (alphabetical characters, symbols, etc.)
android:inputType="text"
However, you want them to only type numbers into the EditText
, because the field represents a monetary value.
- Erase the word
text
, but leave the quotes. - Start typing
number
in its place. After typing "n", Android Studio shows a list of possible completions that include "n".
- Choose
numberDecimal
, which limits them to numbers with a decimal point.
android:inputType="numberDecimal"
To see other options for input types, see Specify the input method type in the developer documentation.
There's one more change to make, because it's helpful to display some hint as to what the user should enter into this field.
- Add a
hint
attribute to theEditText
describing what the user should enter in the field.
android:hint="Cost of Service"
You will see the Design Editor update, too.
- Run your app in the emulator. It should look like this:
Nice job! It doesn't do much yet, but you've got a good start and have edited some XML. The XML for your layout should look something 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"
android:padding="16dp"
tools:context=".MainActivity">
<EditText
android:id="@+id/cost_of_service"
android:layout_width="160dp"
android:layout_height="wrap_content"
android:hint="Cost of Service"
android:inputType="numberDecimal"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Add the service question
In this step, you'll add a TextView
for the question prompt, "How was the service?" Try typing this out without copy/pasting. The suggestions from Android Studio should help you.
- After the close of the
EditText
tag,/>
, add a new line and start typing<TextView
. - Select
TextView
from the suggestions, and Android Studio will automatically add thelayout_width
andlayout_height
attributes for theTextView
. - Choose
wrap_content
for both, since you only need theTextView
to be as big as the text content inside it. - Add the
text
attribute with"How was the service?"
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="How was the service?"
- Close the tag with
/>
. - Notice in the Design Editor that the
TextView
overlaps theEditText
.
That doesn't look right, so you'll add constraints on the TextView
next. Think about what constraints you need. Where should the TextView
be positioned horizontally and vertically? You can check the app screenshot to help you.
Vertically, you want the TextView
to be below the cost of service text field. Horizontally, you want the TextView
aligned to the starting edge of the parent.
- Add a horizontal constraint to the
TextView
to constrain its starting edge to the starting edge of the parent.
app:layout_constraintStart_toStartOf="parent"
- Add a vertical constraint to the
TextView
to constrain the top edge of theTextView
to the bottom edge of the cost of serviceView
.
app:layout_constraintTop_toBottomOf="@id/cost_of_service"
Note that there's no plus in @id/cost_of_service
because the ID is already defined.
It doesn't look the best, but don't worry about that for now. You just want to make sure all the necessary pieces are on screen and the functionality works. You'll fix how it looks in the following codelabs.
- Add a resource ID on the
TextView
. You'll need to refer to this view later as you add more views and constrain them to each other.
android:id="@+id/service_question"
At this point, your XML should look 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"
android:padding="16dp"
tools:context=".MainActivity">
<EditText
android:id="@+id/cost_of_service"
android:hint="Cost of Service"
android:layout_height="wrap_content"
android:layout_width="160dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:inputType="numberDecimal"/>
<TextView
android:id="@+id/service_question"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="How was the service?"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cost_of_service"/>
</androidx.constraintlayout.widget.ConstraintLayout>
5. Add tip options
Next you'll add radio buttons for the different tip options the user can choose from.
There should be three options:
- Amazing (20%)
- Good (18%)
- Okay (15%)
If you're not sure how to do this, you can do a Google search. This is a great tool that developers use when they're stuck.
- Do a Google search for
radio button android
. The top result is a guide from the Android developers site on how to use radio buttons—perfect!
- Skim through the Radio Buttons guide.
Reading the description, you can confirm that you can use a RadioButton
UI element in your layout for each radio button you need. Furthermore, you also need to group the radio buttons within a RadioGroup
because only one option can be selected at a time.
There is some XML that looks like it would fit your needs. Read through it and see how RadioGroup
is the parent view and the RadioButtons
are child views within it.
- Go back to your layout in Android Studio to add the
RadioGroup
andRadioButton
to your app. - After the
TextView
element, but still within theConstraintLayout
, start typing out<RadioGroup
. Android Studio will provide helpful suggestions to help you complete your XML. - Set the
layout_width
andlayout_height
of theRadioGroup
towrap_content
. - Add a resource ID set to
@+id/tip_options
. - Close the start tag with
>
. - Android Studio adds
</RadioGroup>
. Like theConstraintLayout
, theRadioGroup
element will have other elements inside it, so you might want to move it to its own line. - Constrain the
RadioGroup
below the service question (vertically) and to the start of the parent (horizontally). - Set the
android:orientation
attribute tovertical
. If you wanted theRadioButtons
in a row, you would set the orientation tohorizontal
.
The XML for the RadioGroup
should look like this:
<RadioGroup
android:id="@+id/tip_options"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/service_question">
</RadioGroup>
Add RadioButtons
- After the last attribute of the
RadioGroup
, but before the</RadioGroup>
end tag, add aRadioButton
.
<RadioGroup
android:id="@+id/tip_options"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/service_question">
<!-- add RadioButtons here -->
</RadioGroup>
- Set the
layout_width
andlayout_height
towrap_content
. - Assign a resource ID of
@+id/option_twenty_percent
to theRadioButton
. - Set the text to
Amazing (20%)
. - Close the tag with
/>
.
<RadioGroup
android:id="@+id/tip_options"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/service_question"
app:layout_constraintStart_toStartOf="parent"
android:orientation="vertical">
<RadioButton
android:id="@+id/option_twenty_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Amazing (20%)" />
</RadioGroup>
Now that you've added one RadioButton
, can you modify the XML to add 2 more radio buttons for the Good (18%)
and Okay (15%)
options?
This is what the XML for the RadioGroup
and RadioButtons
looks like:
<RadioGroup
android:id="@+id/tip_options"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/service_question"
app:layout_constraintStart_toStartOf="parent"
android:orientation="vertical">
<RadioButton
android:id="@+id/option_twenty_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Amazing (20%)" />
<RadioButton
android:id="@+id/option_eighteen_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Good (18%)" />
<RadioButton
android:id="@+id/option_fifteen_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Okay (15%)" />
</RadioGroup>
Add a default selection
Currently, none of the tip options are selected. It would be nice to select one of the radio button options by default.
There's an attribute on the RadioGroup
where you can specify which button should be checked initially. It's called checkedButton
, and you set it to the resource ID of the radio button you want selected.
- On the
RadioGroup
, set theandroid:checkedButton
attribute to@id/option_twenty_percent
.
<RadioGroup
android:id="@+id/tip_options"
android:checkedButton="@id/option_twenty_percent"
...
Notice in the Design Editor that the layout has been updated. The 20% tip option is selected by default—cool! Now it's starting to look like a tip calculator!
Here is what the XML looks like so far:
<?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"
android:padding="16dp"
tools:context=".MainActivity">
<EditText
android:id="@+id/cost_of_service"
android:hint="Cost of Service"
android:layout_height="wrap_content"
android:layout_width="160dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:inputType="numberDecimal"/>
<TextView
android:id="@+id/service_question"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="How was the service?"
app:layout_constraintTop_toBottomOf="@id/cost_of_service"
app:layout_constraintStart_toStartOf="parent" />
<RadioGroup
android:id="@+id/tip_options"
android:checkedButton="@id/option_twenty_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/service_question"
app:layout_constraintStart_toStartOf="parent"
android:orientation="vertical">
<RadioButton
android:id="@+id/option_twenty_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Amazing (20%)" />
<RadioButton
android:id="@+id/option_eighteen_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Good (18%)" />
<RadioButton
android:id="@+id/option_fifteen_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Okay (15%)" />
</RadioGroup>
</androidx.constraintlayout.widget.ConstraintLayout>
6. Complete the rest of the layout
You're on the last part of the layout now. You'll add a Switch
, Button
, and a TextView
to display the tip amount.
Add a Switch for rounding up the tip
Next, you'll use a Switch
widget to allow the user to select yes or no for rounding up the tip.
You want the Switch
to be as wide as the parent, so you might think the width should be set to match_parent
. As noted earlier, you can't set match_parent
on UI elements in a ConstraintLayout
. Instead, you need to constrain the start and end edges of the view, and set the width to 0dp
. Setting the width to 0dp
tells the system not to calculate the width, just try to match the constraints that are on the view.
- Add a
Switch
element after the XML for theRadioGroup
. - As noted above, set the
layout_width
to0dp
. - Set the
layout_height
towrap_content
. This will make theSwitch
view as tall as the content inside. - Set the
id
attribute to@+id/round_up_switch
. - Set the
text
attribute toRound up tip?
. This will be used as a label for theSwitch
. - Constrain the start edge of the
Switch
to the start edge of thetip_options
and the end to the end of the parent. - Constrain the top of the
Switch
to the bottom of thetip_options
. - Close the tag with
/>
.
It would be nice if the switch was turned on by default, and there's an attribute for that, android:checked
, where the possible values are true
(on) or false
(off).
- Set the
android:checked
attribute totrue
.
Putting that all together, the XML for the Switch
element looks like this:
<Switch
android:id="@+id/round_up_switch"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:checked="true"
android:text="Round up tip?"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@id/tip_options"
app:layout_constraintTop_toBottomOf="@id/tip_options" />
Add the Calculate button
Next you'll add a Button
so the user can request that the tip be calculated. You want the button to be as wide as the parent, so the horizontal constraints and width are the same as they were for the Switch
.
- Add a
Button
after theSwitch
. - Set the width to
0dp
, as you did for theSwitch
. - Set the height to
wrap_content
. - Give it a resource ID of
@+id/calculate_button
, with the text"Calculate"
. - Constrain the top edge of
Button
to the bottom edge of the Round up tip?Switch
. - Constrain the start edge to the start edge of the parent and the end edge to the end edge of the parent.
- Close the tag with
/>
.
Here's what the XML for the Calculate Button
looks like:
<Button
android:id="@+id/calculate_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Calculate"
app:layout_constraintTop_toBottomOf="@id/round_up_switch"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
Add tip result
You're almost done with the layout! In this step you'll add a TextView
for the tip result, putting it below the Calculate button, and aligned with the end instead of the start like the other UI elements.
- Add a
TextView
with a resource ID namedtip_result
and the textTip Amount
. - Constrain the ending edge of the
TextView
to the ending edge of the parent. - Constrain the top edge to the bottom edge of the Calculate button.
<TextView
android:id="@+id/tip_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/calculate_button"
android:text="Tip Amount" />
- Run the app. It should look like this screenshot.
Great job, especially if this is your first time working with XML!
Note that the app may not look exactly the same as the screenshot because the templates may have changed in a later version of Android Studio. The Calculate button doesn't do anything yet, but you can type in the cost, select the tip percentage, and toggle the option to round up the tip or not. You'll make the Calculate button work in the next codelab, so be sure to come back for it!
7. Adopt good coding practices
Extract the strings
You may have noticed the warnings about hard-coded strings. Recall from the earlier codelabs that extracting strings to a resource file makes it easier to translate your app to other languages and to reuse strings. Go through activity_main.xml
and extract all the string resources.
- Click on a string; hover over on the yellow light bulb icon that appears, then click on the triangle next to it; choose Extract String Resource. The default names for the string resources are fine. If you want, for the tip options you can use
amazing_service
,good_service
, andok_service
to make the names more descriptive.
Now verify the string resources you just added.
- If the Project window isn't showing, click the Project tab on the left side of the window.
- Open app > res > values > strings.xml to see all the UI string resources.
<resources>
<string name="app_name">Tip Time</string>
<string name="cost_of_service">Cost of Service</string>
<string name="how_was_the_service">How was the service?</string>
<string name="amazing_service">Amazing (20%)</string>
<string name="good_service">Good (18%)</string>
<string name="ok_service">Okay (15%)</string>
<string name="round_up_tip">Round up tip?</string>
<string name="calculate">Calculate</string>
<string name="tip_amount">Tip Amount</string>
</resources>
Reformat the XML
Android Studio provides various tools to tidy up your code and make sure it follows recommended coding conventions.
- In
activity_main.xml
, choose Edit > Select All. - Choose Code > Reformat Code.
This will make sure the indenting is consistent, and it may reorder some of the XML of UI elements to group things, for example, putting all the android:
attributes of one element together.
8. Solution code
res/layout/activity_main.xml
<?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"
android:padding="16dp"
tools:context=".MainActivity">
<EditText
android:id="@+id/cost_of_service"
android:layout_width="160dp"
android:layout_height="wrap_content"
android:hint="@string/cost_of_service"
android:inputType="numberDecimal"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/service_question"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/how_was_the_service"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cost_of_service" />
<RadioGroup
android:id="@+id/tip_options"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checkedButton="@id/option_twenty_percent"
android:orientation="vertical"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/service_question">
<RadioButton
android:id="@+id/option_twenty_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/amazing_service" />
<RadioButton
android:id="@+id/option_eighteen_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/good_service" />
<RadioButton
android:id="@+id/option_fifteen_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/ok_service" />
</RadioGroup>
<Switch
android:id="@+id/round_up_switch"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:checked="true"
android:text="@string/round_up_tip"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@id/tip_options"
app:layout_constraintTop_toBottomOf="@id/tip_options" />
<Button
android:id="@+id/calculate_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/calculate"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/round_up_switch" />
<TextView
android:id="@+id/tip_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/tip_amount"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/calculate_button" />
</androidx.constraintlayout.widget.ConstraintLayout>
res/values/strings.xml
<resources>
<string name="app_name">Tip Time</string>
<string name="cost_of_service">Cost of Service</string>
<string name="how_was_the_service">How was the service?</string>
<string name="amazing_service">Amazing (20%)</string>
<string name="good_service">Good (18%)</string>
<string name="ok_service">Okay (15%)</string>
<string name="round_up_tip">Round up tip?</string>
<string name="calculate">Calculate</string>
<string name="tip_amount">Tip Amount</string>
</resources>
9. Summary
- XML (Extensible Markup Language) is a way of organizing text, made of tags, elements, and attributes.
- Use XML to define the layout of an Android app.
- Use
EditText
to let the user input or edit text. - An
EditText
can have a hint to tell the user what is expected in that field. - Specify the
android:inputType
attribute to limit what type of text the user can input into anEditText
field. - Make a list of exclusive options with
RadioButtons
, grouped with aRadioGroup
. - A
RadioGroup
can be vertical or horizontal, and you can specify whichRadioButton
should be selected initially. - Use a
Switch
to let the user toggle between two options. - You can add a label to a
Switch
without using a separateTextView
. - Each child of a
ConstraintLayout
needs to have vertical and horizontal constraints. - Use "start" and "end" constraints to handle both Left to Right (LTR) and Right to Left (RTL) languages.
- Names of the constraint attributes follow the form
layout_constraint<Source>_to<Target>Of
. - To make a
View
as wide as theConstraintLayout
it's in, constrain the start and end to the start and end of the parent, and set the width to 0dp.
10. Learn more
Below are links to more documentation on the topics covered. You can find all of the documentation for Android Development on developer.android.com. And don't forget you can do a Google search if you get stuck on something.
11. Practice on your own
Do the following:
- Create a different calculator app, like a unit converter for cooking, to convert milliliters to or from fluid ounces, grams to or from cups, and so on. What fields do you need?