3.4 Building the GUI
In this section, we’ll show the precise steps for building the Tip Calculator’s GUI, including how to customize the Material theme’s primary and accent colors.
3.4.1 GridLayout Introduction
This app uses a GridLayout (package android.widget) to arrange views into four rows and two columns, each indexed from 0 like the elements in an array. You can specify a GridLayout’s number of rows and columns in the Properties window. Each cell can be empty or can hold one or more views, including layouts containing other views. A row’s height is determined by the row’s tallest view. Similarly, a column’s width is defined by the column’s widest view. Figure 3.2 shows the Tip Calculator’s GridLayout labeled by its rows and columns—we drew horizontal lines to delineate the rows and a vertical line to delineate the columns. Views can span multiple rows and/or columns—for example, the Enter Amount TextView in Fig. 3.2 spans both columns in row 0.
Fig. 3.2 | Tip Calculator GUI’s GridLayout labeled by its rows and columns.
When you drag a view onto a GridLayout in the Component Tree, the view occupies the next available grid cell—cells populate the GridLayout left-to-right until a given row is full, then the next view appears in the first column of the next row. As you’ll see, you also can specify the exact row and column in which to place a view. We’ll discuss other GridLayout features as we present the GUI-building steps.
id Property Values for This App’s Views
Figure 3.3 shows the views’ id property values. For clarity, our naming convention is to use the view’s class name in the id property and the corresponding Java variable name. In the first row, there are actually two components in the same grid cell—the amountTextView (which initially displays Enter Amount) hides the amountEditText that receives the user input. As you’ll soon see, we restrict the user’s input to whole-number values entered as integer digits, so the user enters the bill amount $34.56 as 3456. This ensures the user cannot enter invalid input. However, this amount should be displayed as currency. As the user enters each digit, we divide the amount by 100.0 and display in the amountTextView the locale-specific, currency-formatted amount.
Fig. 3.3 | Tip Calculator views labeled with their id property values.
3.4.2 Creating the TipCalculator Project
Follow the steps in Section 2.3 to create a new project using the Empty Activity template. Specify the following values in the Create New Project dialog’s New Project step:
- Application name: Tip Calculator
- Company Domain: deitel.com (or specify your own domain name)
For the remaining steps in the Create New Project dialog, use the same settings as in Section 2.3. Also, follow the steps in Section 2.5.2 to add an app icon to your project.
Once the project is open in Android Studio, in the layout editor, select Nexus 6 from the virtual-device drop-down list (Fig. 2.11). Once again, we’ll use this device as the basis for our design. Also, delete the Hello world! TextView.
3.4.3 Changing to a GridLayout
Recall that the default layout for an Empty Activity is a RelativeLayout. Here, you’ll change that to a GridLayout:
- Click the Text tab at the bottom of the layout editor to switch from the Design view to the layout’s XML text.
- At the top of the XML, change RelativeLayout to GridLayout.
- Switch back to the layout editor’s Design tab.
Specifying Two Columns and Default Margins for the GridLayout
Recall that the GUI in Fig. 3.2 consists of two columns. To specify this, select GridLayout in the Component Tree window, then change its columnCount property to 2—this property appears near the top of the Properties window with the other layout properties. You do not need to set the rowCount—it will be increased as we build the GUI.
By default, there are no margins—spacing that separates views—around a GridLayout’s cells. The material design guidelines recommend 8dp minimum spacing between views:
http://developer.android.com/design/style/metrics-grids.html.
GridLayout can enforce this recommended spacing. With the GridLayout selected in the Component Tree, in the Properties window, check the GridLayout’s useDefaultMargins property (which sets it to true) to use the recommended margins around the layout’s cells.
3.4.4 Adding the TextViews, EditText and SeekBar
You’ll now build the GUI in Fig. 3.2. You’ll start with the basic layout and views in this section. In Section 3.4.5, you’ll customize the views’ properties to complete the design. Then, in Section 3.5, you’ll change the default theme and customize two of its colors. As you add each view to the GUI, immediately set its id property using the names in Fig. 3.3. You’ll add views to the GridLayout using the Component Tree window. If you drop a view in the wrong location in the Component Tree, you can drag it to the correct location.
You may also drag views directly onto the layout editor. For a GridLayout, the layout editor displays a grid of green guidelines to help you position the view. As you drag a view over the grid, the layout editor displays a tooltip indicating the row and column in which the view will be placed if you drop the view at that location.
Step 1: Adding Views to the First Row
The first row consists of the amountTextView and the amountEditText—both occupy the same cell and span two columns. Each time you drop a view onto the GridLayout in the Component Tree window, the view is placed in the layout’s next open cell, unless you specify otherwise by setting the view’s layout:row and layout:column properties. You’ll do that in this step so that the amountEditText and amountTextView appear in the same cell with the amountTextView in the foreground.
This app’s TextViews use the medium-sized font from the app’s theme. The layout editor’s Palette provides preconfigured TextViews named Plain Text, Large Text, Medium Text and Small Text (in the Widgets section) for various text sizes. The Plain Text TextView uses the theme’s default font size. For the others, the IDE configures the TextView’s textAppearance property using the Material theme’s styles for the corresponding font sizes.
Perform the following steps to add to the GridLayout an EditText and a TextView for receiving and displaying the bill amount:
- This app allows you to enter only nonnegative integers, which the app divides by 100.0 to display the bill amount. The Palette’s Text Fields section provides preconfigured EditTexts for various forms of input, including person names, passwords, e-mail addresses, phone numbers, times, dates and numbers. When the user interacts with an EditText, an appropriate keyboard is displayed, based on the EditText’s input type. From the Palette’s Text Fields section, drag and drop a Number EditText onto the GridLayout node in the Component Tree window—this creates an EditText with the id editText in the GridLayout. Change the id to amountEditText. The EditText is placed in the first column of the GridLayout’s first row. Set the EditText’s layout:column to 0 and the layout:columnSpan to 2—these settings ensure that the TextView spans both columns of row 0.
- Drag a Medium Text TextView from the Palette’s Widgets section over the amountEditText in the Component Tree window—a horizontal black line appears below amountEditText, indicating that the TextView will be placed after amountEditText. The IDE creates a new TextView named textView and nests it in the GridLayout node. The default text "Medium Text" appears in the layout editor. You’ll change this in Step 5 (Section 3.4.5). Change the TextView’s id to amountTextView, then set the layout:row to 0, the layout:column to 0 and the layout:columnSpan to 2—these settings ensure that the TextView spans both columns of row 0, as you’ll see once we change the TextView’s background color.
Step 2: Adding Views to the Second Row
Next, add the percentTextView and percentSeekBar to the GridLayout for displaying and selecting the tip percentage (be sure to set each view’s id to the name we specify):
- Drag a Medium TextView (percentTextView) from the Palette’s Widgets section over the amountTextView in the GridLayout node in the Component Tree window. The new view becomes the first view in row 1 (the second row).
- Drag a SeekBar (percentSeekBar) from the Palette’s Widgets section over the percentTextView in the GridLayout node in the Component Tree window. The new view becomes the second view in row 1.
Step 3: Adding Views to the Third Row
Next, add the tipLabelTextView and the tipTextView to the GridLayout for displaying the tip amount:
- Drag a Medium TextView (tipLabelTextView) over the percentSeekBar in the GridLayout node. The new view becomes the first view in row 2 (the third row).
- Drag a Medium TextView (tipTextView) over the tipLabelTextView in the GridLayout node. The new view becomes the second view in row 2.
Step 4: Adding Views to the Fourth Row
Next, add the totalLabelTextView and the totalTextView to the GridLayout for displaying the tip amount:
- Drag a Medium TextView (totalLabelTextView) over the tipTextView in the GridLayout node. This becomes the first view in row 3 (the fourth row).
- Drag a Medium TextView (totalTextView) over the totalLabelTextView in the GridLayout node. This becomes the second view in row 3.
Reviewing the Layout So Far
The GUI and Component Tree window should now appear as shown in Fig. 3.4. The warning symbols shown in the layout editor and the Component Tree window will go away as you complete the GUI design in Section 3.4.5.
Fig. 3.4 | GUI and the Component Tree window after adding the views to the GridLayout.
A Note Regarding the EditText’s Virtual Keyboard
When the virtual keyboard is displayed, the device’s back button () changes to a down button () that enables you to dismiss the keyboard. If you do so, the down button () changes to a back button () that you can touch to return to the previous Activity—possibly a prior app or the device’s home screen.
Normally, you’d touch the EditText to redisplay the virtual keyboard. In this app, however, the EditText is hidden behind a TextView. If you were to dismiss this app’s keyboard, you’d have to leave the app and return to it to redisplay the keyboard. We could programmatically force the keyboard to stay on the screen, but this would prevent the back button from ever being displayed in this app. This, in turn, would prevent you from returning to the previous Activity—a basic Android feature that every user expects.
We used an Android virtual keyboard to demonstrate how to choose the keyboard displayed for a given EditText. Another approach would be to provide Buttons representing the digits 0–9 that always remain on the screen. We could handle their click events and use String manipulation rather than an EditText to keep track of the user input.
3.4.5 Customizing the Views
You’ll now customize additional view properties. As you did in Section 2.5, you’ll also create several String, dimension and color resources.
Step 5: Specifying Literal Text
Next, you’ll specify the literal text for the amountTextView, percentTextView, tipLabelTextView and totalLabelTextView. When a TextView’s text property is empty, its hint property’s value (if you specify one) is displayed—this property is commonly used with an EditText (a subclass of TextView) to help the user understand the EditText’s purpose. We’re using it similarly in the amountTextView to tell the user to enter a bill amount:
- In the Component Tree, select amountTextView and locate its hint property in the Properties window.
- Click the ellipsis (…) button to the right of the property’s value to display the Resources dialog.
- In the dialog, click New Resource, then select New String Value… to display the New String Value Resource dialog and set the Resource name to enter_amount and Resource value to "Enter Amount". Leave the other settings and click OK to create the new String resource and set it as amountTextView’s hint.
Repeat these steps to set the text property for the percentTextView, tipLabelTextView and totalLabelTextView using the values shown in Fig. 3.5.
Fig. 3.5 | String resource values and names.
Step 6: Right Aligning the TextViews in the Left Column
In Fig. 3.2, the percentTextView, tipLabelTextView and totalLabelTextView are right aligned. You can accomplish this for all three TextViews at once as follows:
- Select the percentTextView.
- Hold Ctrl on Windows/Linux or Command on Mac and click the tipLabelTextView and totalLabelTextView. Now all three TextViews are selected.
- Expand the layout:gravity property’s node and check the right checkbox.
Step 7: Configuring the amountEditText
In the final app, the amountEditText is hidden behind the amountTextView and is configured to allow only digits to be entered by the user. Select the amountEditText and set the following properties:
- Set the digits property to 0123456789—this allows only digits to be entered, even though the numeric keypad contains other characters, such as minus (-), comma (,) and period (.).
- Set the maxLength property to 6. This restricts the bill amount to a maximum of six digits—so the largest supported bill amount is 9999.99.
Step 8: Configuring the amountTextView
To complete the amountTextView’s formatting, select it and set the following properties:
- Delete the default value of the text property ("Medium Text")—we’ll programmatically display text here, based on the user’s input.
- Expand the layout:gravity property’s node and set the fill to horizontal. This indicates that the TextView should occupy all remaining horizontal space in this GridLayout row.
- Set the background property (which specifies the view’s background color) to a new color resource named amount_background with the value #BBDEFB—a light blue color chosen from Google’s material design color palette.
- Add padding around the TextView. A view’s padding specifies extra space around a view’s content. The all property specifies that the padding amount should be applied to the top, right, bottom and left of the view’s contents. You may also set the padding for each of these individually. Expand the padding property’s node, click the all property, then click the ellipsis button. Create a new dimension resource named textview_padding with the value 12dp. You’ll use this resource again shortly.
- Finally, add a shadow to the view by setting the elevation property to a new dimension resource named elevation with the value 4dp. We chose this value for demonstration purposes to emphasize the shadow effect.
Step 9: Configuring the percentTextView
Notice that the percentTextView is aligned higher than the percentSeekBar. This looks better if it’s vertically centered. To do this, expand the layout:gravity property’s node, then set the center value to vertical. Recall that you previously set the layout:gravity to right. The combination of these settings appears in the layout XML as
android:layout_gravity="center_vertical|right"
A vertical bar (|) is used to separate multiple layout:gravity values—in this case indicating that the TextView should be centered vertically and right aligned within the grid cell.
Step 10: Configuring the percentSeekBar
Select percentSeekBar and configure the following properties:
- By default, a SeekBar’s range is 0 to 100 and its current value is indicated by its progress property. This app allows tip percentages from 0 to 30 and specifies a default of 15 percent. Set the SeekBar’s max property to 30 and the progress property to 15.
- Expand the layout:gravity property’s node and set the fill to horizontal so the SeekBar occupies all horizontal space in the SeekBar’s GridLayout column.
- Set the layout:height property to a new dimension resource (seekbar_height) with the value 40dp to increase vertical space in which the SeekBar is displayed.
Step 11: Configuring the tipTextView and totalTextView
To complete the formatting of the tipTextView and totalTextView, select both and set the following properties:
- Delete the default value of the text property ("Medium Text")—we’ll programmatically display the calculated tip and total.
- Expand the layout:gravity property’s node and set the fill to horizontal so each TextView occupies all horizontal space in the TextViews’ GridLayout column.
- Set the background property to a new color resource named result_background with the value #FFE0B2—a light orange color chosen from Google’s material design color palette.
- Set the gravity property to center so the calculated tip and total amounts will be centered within these TextViews.
- Expand the padding property’s node, click the ellipsis button for the all value, then select the dimension resource named textview_padding that you created previously for the amountTextView.
- Finally, add a shadow to each view by setting the elevation property to the elevation dimension resource you created earlier.