UI Design: Buttons, Menus, and Dialogs
The UI design determines the usability of your application, which will ultimately determine its success and even its profitability if you are selling it. We’ll build on what we learned in Chapter 6 as UI elements in Android are View classes (widgets) and are grouped together using ViewGroup classes (layout containers).
A standard UI is composed of a number of familiar components that can be used by your application’s users to control their user experience (often called the UX). These UI elements include items such as buttons, check boxes, radio buttons, menus, text fields, dialog boxes, progress bars, system alerts, and similar screen-based elements that are available to us under Android as widgets as we learned in Chapter 6.
This chapter covers how to use several of the most important Android widgets for UI design. First, we’ll cover adding image buttons, text, and images to your UI. Then you’ll learn about the different types of menus available. Finally, we’ll cover displaying dialogs, including alerts, which carry messages to your application user. There’s a lot of cool stuff to cover, so let’s get started.
Using Android UI Elements (Widgets)
One of the foundational areas of user interface (UI) design is creating and placing the functional elements of the design that allow your user to seamlessly interface with your application. These elements include buttons, text fields, check boxes, radio buttons, scrollable lists, and the like. We can’t cover all of these in one chapter, but we can cover some of the more useful and visually impressive UI elements, just in case you need to make your apps stand apart from the crowd!
One of the most impressive types of user interface elements is the image button, which is an image that is a button itself or an icon on a button that visually represents what that button will do. In this next section we will learn how to combine an Android ImageButton widget along with a TextView widget and an ImageView widget to show how these Android View Classes can be implemented to add some graphics-intensive UI elements to your layout containers that we learned about in Chapter 6. This will provide a good foundation for then learning more about using graphics in Android in Chapter 8 which covers graphics design in Android.
Android has all of the standard UI elements already coded and ready to use in a single package called android.widget. Here, we’ll explore how to add an image button, text area, and image to your app’s UI.
Note Recall that a package in Java is a collection of ready-to-use classes that you can leverage within your application. You just need to tell Java that you are going to use them by importing them via the Java import command.
Adding an Image Button to Your Layout
In Chapter 6, we crafted a UI that included the Button class, which is used to create the standard Android system format buttons, and lets you do so with the greatest of ease. Now, we’ll look at the more complex ImageButton class. For professional, customized, high-end graphical UIs, this is the class that you will need to use to gain the most visual control over the user experience as well as increased wow factor.
The android.widget package’s ImageButton class allows you to use your own imagery to create custom multistate buttons that are cooler looking than the standard buttons that come standard with the Android operating environment.
There is a distinct work process to creating a successful multistate 24-bit or 32-bit PNG image button; one that will composite perfectly over background imagery if the button is using an 8-bit alpha channel. We’ll get into much more detail about PNGs and alpha channels in the next couple of chapters.
Android supports 24 bits of PNG image data, with another 8 bits of anti-aliased image transparency channel (requiring another 8-bit alpha channel). Let’s do the math: 24 + 8 = 32. So, what we really have is a 32-bit PNG image, with 8 bits of data for each of the red, green, and blue image channels, and another 8 bits of data for the alpha (transparency) channel. Therefore, 24-bit images are usually called RGB images, and 24-bit images with 8-bit alpha channels are usually called 32-bit images or RGBA (Red Green Blue Alpha) images.
In case you’re not familiar with some of the terms I used in the previous description, here are some brief definitions:
Defining Multi-state Image Button Graphics in XML
The XML markup is significantly more complex for multistate image buttons than it is for regular buttons. Your XML file needs to tell Android which image to use for each state of the button:
Let’s look at the code for our button1.xml file, which we will reference later when we create our ImageButton XML entry in the activity_main.xml file that goes in the /res/layout folder. You don’t need to create this file now.
<selector xmlns:android="http://schemas.android.com/apk/res/android ">
<item android:state_pressed="true"
android:drawable="@drawable/button1_pressed" />
<item android:state_focused="true"
android:drawable="@drawable/button1_focused" />
<item android:drawable="@drawable/button1_normal" />
</selector>
The first line defines a selector tag and points to the Android XML naming schema, as you have seen in previous chapters. A selector tag allows selection between several <item> options contained inside (nested within) it, as you may have guessed already. Inside the selector tag, we nest three item tags to show which drawable (bitmap) images to use (to select) for state_pressed=true, state_focused=true, and finally the default or normal button state. These item tags must be in the exact order outlined above, as they are evaluated by Android in that order (Is it Pressed? Does it have Focus? Is it not Pressed or does not have Focus?).
For this XML code to work we must have three 32-bit bitmap PNG images in each of our project’s /res/drawable-dpi folders named button1_pressed.png, button1_focused.png, and button1_normal.png.
Just like we did with our icons, we will have to go through the digital imaging work process that yields buttons optimized for LDPI, MDPI, HDPI, and XHDPI pixel density screens because Android devices now span smartphones to tablets to e-readers to iTV sets. So we will really be creating a dozen image assets for each ImageButton UI element that we utilize in our screen design. We’ll do this after we create our new UI design project (next), and before we create and code our UI design project, so that our app’s image assets are ready for use before we actually write the code that tries to access them.
Note Recall that each of the PNG image file names must use only lowercase letters and numbers and also can use the underscore character. These are Android’s file naming rules. If you stray from this file naming rule at all, you will generate errors, warnings, and debugging headaches! So memorize this rule now to minimize future wasted debugging time!
The first item tag has an android:state_pressed attribute, which is set equal to true, and a second android:drawable attribute, which is set equal to the location of the file and its name (sans the .png extension, as we learned about previously) and will automatically point to the correct /drawable-dpi/ folder based on what screen density Android detects that your app is running on.
The @ equates to your project’s resources folder, /project/res/, so in this case, a low DPI resolution image for @drawable/button1_pressed will equate to C:/Users/YourName/workspace/UI_Design/res/drawable-ldpi/button1_pressed.png in the Android compiler (as well as the folders for the MDPI, HDPI, and XHDPI image assets, depending on what resolution device Android detects that you are using). The other item tags follow the same format as the first one.
Creating the UI Design Image Button Project in Eclipse
Now that we’ve reviewed the concepts, let’s create the project for real. As you’ve done in previous chapters, fire up Eclipse and use the right-click Close Project command on your LinearLayouts project folder and then select File New Project Android Application Project to create a new Android application project.
We’ll create the UI_Design Project first, so that Eclipse will create a nice graphic for us that we can modify with GIMP and then use for our ImageButton for this example. Let’s get started!
In the New Android Application Project dialog sequence, set the project configuration options as follows:
If you need to refresh your memory on how to fill out all of the New Project Dialogs, please revisit the screenshots in Chapters 4 and 6 now. I’ll include the main (initial) dialog in Figure 7-1 to show our primary project naming settings.
Figure 7-1 . Naming our UI_Design project, application, and package in Eclipse
Creating Our Three UI Design Image Buttons in GIMP 2.8
The first thing that we need to do is to create the three button graphics that we will use to show you how to create multistate image buttons in Android using the ImageButton widget. Because Android has provided us a cool graphic with an alpha channel (transparency) called ic_launcher.png in our new project creation process, let’s use that for our ImageButton graphic, as it’s already in our /res/drawable/ folders, now that we have created our UI_Design Project.
You will need to go through the work process shown below (we’ll use the XHDPI image asset for our example) on each of the ic_launcher.png files in each of the four /drawable-dpi/ folders. Remember that they all need to be named the same way, because Android will differentiate between which file is which using the folder name and not the file name.
Fire up GIMP from your OS TaskBar and go into the File Open Image menu sequence to access the Open Image Dialog shown in Figure 7-2. Navigate using the left file navigation pane of the dialog to your C:/Users/YourName/workspace/UI_Design/res/drawable-xhdpi/ folder and select the ic_launcher.png file as shown in Figure 7-2 and then click on the Open button.
Figure 7-2 . Find and Open the ic-launcher.png file in the /drawable-xhdpi/ folder
Next, click on the Colors Menu at the top of GIMP, as shown in Figure 7-3, and select the Hue-Saturation submenu item. Notice that GIMP is as good as Eclipse is at giving you a context-sensitive tooltip telling you what that menu selection will do before you select it. In this case, it tells us we are about to adjust the color (hue) value of the graphic that we have just opened.
Figure 7-3 . Selecting the Hue-Saturation tool from the Color Menu in GIMP 2.8
Once we have the Hue-Saturation color adjustment tool dialog on the screen, use the HUE slider or the Hue value numeric entry box on the right to shift our Hue (color) value backwards in the color wheel by 90 degrees, or a value entry of −90 if you wish to type it in. Make sure that the Preview Checkbox has a check in it (is selected for use) as shown in Figure 7-4, so that you can see the color change in the ic_launcher graphic go from blue to green. This will make our ImageButton graphic turn green when our users touch it. When everything is set, and you have a nice green color, select the OK button to make the color change permanent.
Figure 7-4 . Changing the ic_launcher color value from blue to green
Because the “Pressed” button state is more effective when it animates when the user touches it on the screen, let’s also rotate it 90 degrees so the little guy (or gal) depicted in the image turns their head to the side. To do this, we click on the Image Menu at the top of GIMP and select the Transform submenu and then the Transform 90 degrees counter-clockwise sub-submenu as shown in Figure 7-5.
Figure 7-5 . Image Transform Menu path for rotating our Pressed State graphic 90 degrees counter-clockwise
Now we are ready to use the GIMP File Export dialog to save our button1_pressed.png graphic file to it’s new name and target location in the /drawable-xhdpi/ folder in our resource folder. Select the File Export menu as shown in Figure 7-6 to bring up the File Export Dialog so we can save our first of three ImageButton state files.
Figure 7-6 . Using the File Export utility to save the new Pressed State graphic PNG
Name the button graphic button1_pressed.png in the Export Image dialog’s name field as shown in Figure 7-7 using the Places Pane on the left to show GIMP where you want to save the file. Note the path to the File will also be shown graphically at the top of the dialog underneath the file name, next to the “Save in folder:” specifier. Once everything is set correctly, use the Export button to save the first of your three ImageButton image graphics to the /res/drawable-xhdpi/ folder.
When the PNG format settings dialog comes up make sure to use the same PNG settings that we used back in Chapter 4 in Figure 4-34 (just in case you have forgotten which of these options need to be selected).
Next, let’s create the button1_focused.png button graphic by using the GIMP Edit Undo feature (or the CTRL-Z keystroke sequence) twice, to undo the rotation and the color changes, taking us back to the original blue image. Another way to do this would be to use the File Revert function, or to use the File Close function (without saving, of course), and then to use the File Open on the ic_launcher.png file again, as we did at the beginning of this work process back in Figure 7-2.
Figure 7-7 . Saving the button1_pressed PNG file to the /drawable-xhdpi/ folder
Next we are going to apply the same Color Hue-Saturation menu sequence that we used (shown previously in Figure 7-3) to turn our ImageButton graphic from blue to green, but this time we are going to turn it red to indicate that it has the focus, and is in use or is the one last (currently) used.
To do this we will use a color rotation value of 150 degrees clockwise (positive) around the color wheel from blue, which as you can see in Figure 7-8 gives us a nice bright red color result in our button image. Make sure that you have the Preview Option checked so that you can see what the dialog is doing to your image as you play around with the color adjustment options.
Figure 7-8 . Creating the button1_focused.png graphic using the Colors Hue-Saturation... tool
Once you have a nice red color, go through the steps shown in Figure 7-6 and 7-7, except that you will want to use the file name: button1_focused.png for this red version that will turn your ImageButton red when it is in use! Pretty cool! Now finally let’s create our button1_normal.png ImageButton state graphic so that it is different from our application launcher icon, and we’ll be ready to code!
Finally we are going to apply yet again the same Colors Hue-Saturation menu sequence that we used (shown previously in Figure 7-3) to turn our ImageButton graphic from blue to green, but this time we are going to turn it Amber to indicate our Normal (default) Image Button state. Don’t forget the two Undo steps that will bring your button back to it’s original blue state, just like we did before.
To do this we will use a color rotation value of 160 degrees counter-clockwise (negative) around the color wheel from blue, which as you can see in Figure 7-9 gives us a rich amber color result in our button image. Make sure that you have the Preview Option checked so that you can see what the dialog is doing to your image as you play around with the color adjustment options.
Figure 7-9 . Creating the button1_normal.png graphic again using the Colors Hue-Saturation... tool
Once you have an acceptable amber color, again go through the steps shown in Figure 7-6 and 7-7 except that this time you will want to use the file name: button1_normal.png for this amber version that will be the default image (state) used for your button.
Next we need to create the XML file that will show Android which of the button states to select for each of the user actions that will be involved with animated buttons: Normal (no action), Pressed (touched), and Focused (last touched). Let’s get into that now! Open up Eclipse and take a look in your UI_Design Project resource folder under the /res/drawable-xhdpi/ folder to make sure that all of your new ImageButton states (assets) are ready for use. This is shown in Figure 7-10.
Figure 7-10 . UI_Design Project resource folder and drawable-xhdpi sub-folder with ImageButton assets
You now have an empty Eclipse project loaded with image assets. Next, we’ll create the button1.xml file so that we can add the button state definition XML, which we looked at earlier in the chapter.
Open the project tree on the left in the Package Explorer tab, and expand the /res folder by clicking the arrow. Then right-click the drawable-xhdpi folder and select New File, as shown in Figure 7-11.
Figure 7-11 . Creating a new file in the /res/drawable-xhdpi/ folder to hold our button1.xml XML markup
In the New File dialog, ask Eclipse to create the file button1.xml in the UI_Design/res/drawable-xhdpi folder, as shown in Figure 7-12. Then click Finish to create an empty text file. This is one of the most basic ways that you can have Eclipse create a new, empty text file for you. We will cover other ways of creating new XML files in later chapters.
Figure 7-12 . Specifying the drawable-xhdpi folder and button1.xml file name in the New File dialog
Click the button1.xml tab at the top of your screen, and then type in the XML code that defines the selector and item tags for setting the three different image button states:
<selector xmlns:android="http://schemas.android.com/apk/res/android ">
<item android:state_pressed="true"
android:drawable="@drawable/button1_pressed" />
<item android:state_focused="true"
android:drawable="@drawable/button1_focused" />
<item android:drawable="@drawable/button1_normal" />
</selector>
If you enter this XML markup before you create your three image file assets, you’ll notice that Eclipse will show you that there are three errors in the markup relating to the missing image file assets. Place your mouse over the red X on the left margin by the markup code. This pops up a diagnostic message regarding why Eclipse thinks this code needs your attention, and you will be informed that your code references image assets that do not yet exist or Eclipse cannot locate.
If you have added them but Eclipse cannot “see” them, then right-click on your UI_Design project folder and select the “Refresh” option, and the error flags will disappear as Eclipse will “refresh” it’s view of your project assets and find the unrecognized (missing) file references. Once everything matches up then Eclipse will show your code in a clean (unwarning laden) environment, as shown in Figure 7-13.
Figure 7-13 . The button1.xml code and matching button1 state PNG files in Eclipse
Note Once we have valid XML specifiers and code in place, the Eclipse error messages will disappear. But this does show us how Eclipse is watching out for you in real time, and offering warnings about what might be missing, what might generate compiler errors, and other common problems. You will observe this throughout your use of the Eclipse IDE.
Editing the activity_main.xml File
Next, open the /res/layout/ folder and right-click the activity_main.xml file to open it for editing. Notice that our image button source files now appear inside of the Package Explorer pane.
We need to replace the default text tag in the activity_main.xml file with an ImageButton tag, as follows:
<ImageButton android:id="@+id/button_one"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/button1"
android:contentDescription="@string/app_name">
</ImageButton>
Figure 7-14 shows the IDE at this point.
Figure 7-14 . Eclipse with a default RelativeLayout container and a new ImageButton tag added on the inside
The first attribute adds an ID of button_one to the ImageButton so we can access it inside our Java code. The next two lines define the width and height of the image button via the wrap_content attribute—all very standard Android programming fare.
The next line accesses the button1.xml file that we created to reference the various image button states. Notice that you do not need to add the .xml extension here, just as you don’t need to add the .png for your graphic files. Finally, we have the android:contentDescription tag set to our app_name variable that we already defined in our strings.xml file as UI Design.
The Content Description tag is a relatively new tag for ImageView and ImageButton objects that is there for accessibility purposes, primarily for the sight and hearing impaired. If you do not include an android:contentDescription tag in your ImageView or ImageButton UI element widgets, Eclipse will place a warning (yellow triangle) symbol next to the (in this case) ImageButton tag in the left margin. This warns you that you will need to add this tag for accessibility reasons, at least if you want to get rid of this warning icon. Note that your code will still compile and run without it.
To provide this accessibility for your UI elements, you would need to define a text variable in your strings.xml file that describes each of your visual UI elements in a way that if someone who is impaired was navigating your UI, they will know what element functions they are dealing with (have pressed or focus status).
In this case because the ImageButton is a UI design element, I am simply using an existing variable in strings.xml so that we do not have to go into the strings.xml and create a new variable, as we have already learned how to do that in previous chapters, and don’t really need the extra practice here.
Figure 7-15 shows how our UI Examples app looks when run in the Android 4.1 emulator (right-click UI_Design folder and select Run As Android Application).
Figure 7-15 . Our multistate image button running in the Android 4.1 emulator
When you click the image button, it rotates left and changes color from amber to green and uses the standard blue background to highlight the button being clicked.
Because we want just the nontransparent part of the image to be the button, which is why we use transparency and an alpha channel in GIMP 2.8, we will need to also set a background color, or transparency, for the ImageButton widget itself next. This will pass the transparency in the Image through the ImageButton transparency to whatever is behind both of these design elements. In this case, it will remove the gray background color setting of the ImageButton widget (replacing it with transparency) and let the white background color setting of the RelativeLayout container through.
Replacing the Default Background
We usually do not want to use the default Android ImageButton solid grey color background for a graphic image button, as we normally want the button image to seamlessly overlay the background content, usually a background image. We want the ImageButton background to be transparent, so we can use this ImageButton to put an image on top of a button and its text, or in this case, allow us to make the image (the nontransparent portion, anyway) itself into a button.
In this example, we are changing the color of the button, rather than changing the size or shape of the button, so the transparent area remains exactly the same, pixel for pixel, between the different image state graphics. Thus, we can either set the background image to our normal button state (which has transparency exactly where we need it to be), or we can set the background color using a 32-bit color value setting that features a 100% transparent 8-bit alpha channel by using the #00000000 setting (which means zero red, zero green, zero blue, zero alpha). This is similar to setting HTML color with the pattern #RRGGBBAA. This is the most elegant solution because it uses eight characters of code (in the form of a parameter) instead of an image asset to accomplish what we want, and more importantly because it accommodates image states that may have differently shaped alpha channel regions. Let’s implement background transparency now.
We’ll do this using the Graphical Layout Editor, so that you get additional practice using this cool Eclipse design tool that helps you design your UI widgets and layouts interactively without having to write lots of XML code.
Click the activity_main.xml tab at the top of your screen, and then click the Graphical Layout Editor tab at the bottom of the pane, which will then render your XML for the ImageButton (see Figure 7-16) so that you can see what the XML code will look (render) like when it is run in the Android 4.1 emulator. As you have seen in previous chapters, Eclipse will render your XML markup exactly as it would look in the emulator. Eclipse also provides (on the left) drag-and-drop widgets and layouts, so you can visually design your UI. The normal work process is to switch back and forth between the XML markup coding tab and the Graphical Layout Editor tab, so you can make sure your XML code is nested properly. This is also a great way to learn XML layout and UI coding in Android.
Figure 7-16 . Using Graphical Layout Editor and Properties tabs to set an image background value to transparent
An even more useful tab is the Properties tab at the right side of the screen. This tab shows all of the properties assigned or available to the UI element tag that you have selected in the Graphical Layout Editor. Click the ImageButton element, and a blue line with resizing handles will surround the ImageButton, showing you what is currently actively selected. In the Properties tab, you will see all of the properties and variables that you can set and customize for the ImageButton class.
Click the Background property in the Properties tab to highlight it. Notice that for many of the parameter option fields in the Properties Pane that Eclipse provides a button with three dots (called an “ellipse” in coding terms) on it; this is used to search for a file to use as a background image.
Because we are just going to set the background value to transparent, we do not need to use this file locator button for this particular example. Instead, let’s type the transparency value of #00000000 into the field next to Background in the Properties tab, as shown in Figure 7-16. Then click somewhere else in the IDE, or hit the return key to accept the value. The value will then be accepted and the results displayed in the Graphical Layout Editor tab.
That finishes up our custom image button. If you want to confirm that our ImageButton has no background, and changes color and rotates as its own button now, right-click on the UI_Design folder, and Run As Android Application to view your success! I’ll include a partial view of the emulator in Figure 7-17 to show the button without any background coloring. It looks much more professional because you can’t see the boundaries of its UI container (in this case the ImageButton Tag/Widget). Click it and it turns green and rotates—but now, just the circular part!
Figure 7-17 . Running the ImageButton in the 4.1 emulator to see transparent background
Next, let’s take a closer look at how to add text to your application’s UI, as text is such an important element of any application.
Adding a TextView Widget to Your Layout
Besides buttons, another very common UI element is text. Android provides the TextView class to implement text in a UI. We have already seen this UI element briefly in our Hello Absolute Beginner App in Chapter 4 and our LinearLayout App in Chapter 6, so let’s get a little bit more practice with it here, and explore some of it’s other setting parameters.
Because we have been leveraging the Graphical Layout Editor in Eclipse, let’s continue to explore its functionality because it’s a great learning tool for an absolute beginner. Click the left header bar called Form Widgets to open the form widgets selection view. Clicking these headers will toggle them open, and shut others that are open at any time (as we have seen in Chapters 4 and 6).
Next, click the scrollbar (gray, with a tiny arrow) if you don’t see the TextView widget, which should be at the top left of the widgets listed. Select and drag (and drop) it into the Layout view window under the ImageButton. Our TextView is now in the UI graphical layout view and is ready to customize by using the Properties tab at the right side of the Eclipse IDE. Let’s do that now.
Scroll down to the Text properties and set up some custom values, such as Sample Text, and a text color of dark gold to match the ImageButton default image (an RGB value of #777722 will work well; this is a hexadecimal numeric representation of a 24-bit value). Figure 7-18 shows the Eclipse IDE at this point.
Figure 7-18 . Using the Eclipse Graphical Layout Editor to add and configure a TextView widget
Finally, we’ll set a DIP (device independent pixel) value for padding, so there is some space around our TextView. Scroll to the Padding properties in the Properties tab at the right side of your Eclipse IDE, and type in 12dip, as shown in Figure 7-19, with no spaces between the 12 and the dip. Then click another field, and you will see the text space itself out. If you can’t find the Padding parameter field, notice that there are little plus and minus sign UI widgets inside of the Properties Pane. Click the minus sign next to the Layout Parameters that will close that grouping of parameters and then click on the plus sign next to the View (parameters) that will open up the parameters for items like Padding and Focus. Leave the TextView parameters widget closed (which will show a plus sign, whereas open will show a minus sign) as shown in Figure 7-19.
Figure 7-19 . Setting the padding value for our TextView via the Properties tab in the Eclipse IDE
Finally, let’s add another popular type of UI element used for design: the image. Go to the code bundle for this book and copy the two 32-bit PNG image files named image1.png and image2.png into your UI_Design/res/drawable-xhdpi folder.
Right-click the UI_Design folder in the Package Explorer pane, and select the Refresh command to update the project inside of Eclipse, or select the folder and then hit the F5 function key at the top of your keyboard. Both work processes will achieve the same result and Eclipse will “see” the new image files.
Now, let’s add an ImageView tag to our XML. To do this, drag the ImageView from the Images & Media drawer on the left, and then drop it under the TextView as shown in Figure 7-20. As you can see in the screenshot, the Graphical Layout Editor gives us a real-time code view (using the tooltip, which changes it’s tag parameter data display in real time as you drag the UI element to determine your UI widget placement) of what our XML parameters are going to be if we drop the widget at exactly that location. Kudos to the Eclipse/ADT UI designers for an amazing GLE feature. This now gives us a RelativeLayout ViewGroup containing our ImageButton, TextView, and ImageView tags (remember that these are all Views or widgets).
Figure 7-20 . Dragging an ImageView widget onto our RelativeLayout UI container in the Eclipse Graphical Layout Editor Tab
Once you drop the ImageView into place, Eclipse automatically opens the Reference Chooser dialog, showing all of the image assets it has found (in the /res/drawable-xhdpi folder, in this case). Select image1 for our ImageView source imagery, as shown in Figure 7-21. Click the OK button to select image1.png and close the dialog.
Figure 7-21 . Choosing our image1 resource via the Reference Chooser dialog, accessed by dropping the ImageView in our RelativeLayout container
In your Graphical Layout Editor tab, you will now see the image and how its transparency area composites smoothly with the white background color.
Later, when we add a menu to our app, we will change the background color to black to show how this image transparency can help with UI compositing over different background colors or imagery.
So now in the next 4.1 emulator screen, you will see our ImageButton, TextView, and ImageView with enough screen area to hold a bottom menu with five menu items. Right-click on the UI_Design project folder, and select Run As Android Application to see the results of your work, as shown in Figure 7-22. We’ll add the bottom menu in the next section, so that you can learn about how to add useful menus to your Android applications.
Figure 7-22 . Running our completed UI design in the Android 4.1 emulator
Menus in Android are quite different from the top-mounted text menus found directly beneath the title bar in PC applications. The menu function on a smartphone or tablet is a bit different for ease of use, and is sometimes an actual physical button called Menu on some Android smartphones and tablets. Other Android devices may have a soft button or touchscreen button area for menu access, or even a Menu button on a remote control for GoogleTV. Nevertheless, the menu function is an important one in Android, as well as in application development in general, so we’re covering it in detail in our UI Design chapter.
Pressing the Menu button calls up a menu, which is—you guessed it—at the bottom of the screen, instead of at the top. To make it even more user-friendly, it is composed of five large rectangular icons stacked on top of each other that can be easily touched to control your application features.
For our application, we will have our menus do things with our ImageView object, background color, and alert dialog (which we’ll add later on in this chapter), so that everything we cover in this chapter ties together nicely in one single UI_Design application.
Creating the Menu Structure with XML
As you might have guessed, you set up your entire menu structure in an XML file. In fact, you encountered menu inflater code in the Java that your New Project Android Application Blank Activity generated for you! Once you learn how to code menus in this section, you will be able to modify that bootstrap menu inflating code and turn it into your own application’s menu system.
The menu XML file goes in a /res subfolder named /menu, as required by Android. This folder is created for you by the New Android Application Project functionality, so it’s all ready for us to use. In fact, it has a default activity_main.xml file with the single menu item XML already in it for us, ready to open and edit.
You are probably wondering why Android (via the File New Project Android Application project creation helper) named both our Menu and Layout folder XML names with the activity_main name that Android specified as a default in the new project creation sequence of screens. It may seem confusing now, but there is a very good reason for it, and you are already used to files with exactly the same name in different folders being completely different assets, as that is how multiresolution image assets are handled in the /res/drawable-dpi/ folders. Same concept here.
The reason why this is done becomes clearer as you develop more complex apps with multiple activities (screen layouts containing UI elements and menus), because each set of Layout and Menu folders has their own XML definition with exactly the same name, thereby grouping them logically together by name. Android figures that developers are smart enough to know (remember) that Menu-related XML is in the /res/menu/ folder and that Layout (UI) XML is in the /res/layout/ folder. So if you had an activity_alternate.xml file for a second UI screen (which we actually will, in a later chapter) the widget UI layout activity_alternate.xml file would live in /res/layout/ and the activity_alternate.xml for the second screen’s menuing system would live in /res/menu/. Got it?!
Let’s open up the activity_main.xml file in our /res/menu/ subfolder and type in the XML shown below to create our five button menu. The easiest way to do this is to edit the first item text to match what we want, and then to copy and paste it four times underneath it, and edit a few minor parameters to differentiate each button.
<menu xmlns:android="http://schemas.android.com/apk/res/android ">
<item android:id="@+id/buttonone"
android:title="@string/showimage1"
android:orderInCategory="100"
android:showAsAction="never" />
<item android:id="@+id/buttontwo"
android:title="@string/showimage2"
android:orderInCategory="200"
android:showAsAction="never" />
<item android:id="@+id/buttonthree"
android:title="@string/showwhite"
android:orderInCategory="300"
android:showAsAction="never" />
<item android:id="@+id/buttonfour"
android:title="@string/showblack"
android:orderInCategory="400"
android:showAsAction="never" />
<item android:id="@+id/buttonfive"
android:title="@string/showalert"
android:orderInCategory="500"
android:showAsAction="never" />
</menu>
The menu XML tag is fairly straightforward. It simply declares the location of its XML schema definition and inside (before the </menu> specifier) it contains nested item tags that specify attributes for each menu item to be added. The Android menu holds five items comfortably as you will see here. Most Android applications use five or fewer menu items per activity or UI screen.
Each of the item tags has the following five attributes:
Figure 7-23 shows the completed UI_Design/res/menu/activity_main.xml file.
Figure 7-23 . View of the /res/menu/ folder and the activity_main.xml menu file showing menu and item tags
Next, we’ll go into the strings.xml file in the /res/values folder (located below the menu folder in the Package Explorer pane in Figure 7-23) to edit our application’s string constants. We’ll add the text for our five menu items. Follow these steps to add the five /res/values/ folder’s strings.xml file data values that are referenced inside of our /res/menu/ folder’s activity_main.xml file:
1. Right-click the strings.xml file and select Open to open it in a tab for editing in the Eclipse IDE, as shown in Figure 7-24.
Figure 7-24 . Adding string values for our five menu items in the Resources Editor in Eclipse
2. Click the Resources tab at the bottom of the pane to see a visual representation of the string data resource values in the strings.xml file. Notice that besides string (text value) resources there are also color, dimension, and other kinds of resources that can be represented as string values in the strings.xml file in the /res/values/ folder.
Tip Remember that if you want to see the XML, click the strings.xml tab next to the Resources tab. You can switch back and forth between the code view and the helper view, which is a great way to learn how to code XML UI elements!
3. Click the Add button to bring up the dialog shown on the right in Figure 7-24. We have again combined two screens in one here to save space and time. Select String and click OK to add a string value to our strings.xml file.
Figure 7-25 . Entering String Value Parameters in the resource dialog as part of the Add String Resource work process
4. In the area on the right, in the Name field, enter showimage1. In the Value field, enter IMAGE ONE. Click on the Add button to add this string value to the strings.xml file and simultaneously request the string value for your next string data entry.
5. Repeat step 4 to add four more string values with the following names and values:
6. Set our default white background color of #FFFFFF as a Color object, as shown in Figure 7-26, by selecting a Color Data Object (rather than a String Data Object) on the last two Add Data Value sequences.
Figure 7-26 . Adding the two background color string data resources in the strings.xml file via the Eclipse Resources Editor tab
7. Add a black background called background2, using a value of #000000. To add this to the list on the left, click the Add button as if you were going to add another value, and simply leave the data fields blank and exit the Resources Editor.
If you want some practice using the Remove Button, and want to be meticulous in your programming and make sure that there are no unused string variables in your strings.xml file, you can select (and Remove) the menu_settings variable that ADT created for us in the New Project sequence, as we have replaced that needed variable with five of our own, and it will thus be unreferenced in any code, and can therefore be deleted (but does not absolutely have to be). Figure 7-27 shows the strings.xml Resource Editor Pane after we have added our five menu title and two background color string variables.
Figure 7-27 . Android Resources Editor and Outline tabs showing the seven added resources
Inflating the Menu Structure via Java
Now it is time to add in our Java code, which inflates our menu from the XML file into our application’s memory. The term inflating a resource describes the process of the Android operating system taking the data definition described in an XML file and populating a Java object that can be accessed and used in Java with that data. In this case, it is our activity_main.xml object from the /res/menu/ folder, which contains five menu selection buttons, their settings, and their text captions.
Here are the three lines of Java code that Eclipse so generously added to our MainActivity.java file for us during the File New Project Android Application Project creation operation:
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
Android has a dedicated Java object for inflating XML code constructs into a Java object-based format for use with Java. This is precisely what you are seeing here inside of the onCreateOptionsMenu() method, which uses the .inflate() method and the R.menu.activity_main path to our activity_main.xml file. This method creates a MenuInflater object, which contains our inflated menu objects. The OS then “gets” the MenuInflater object and puts into memory via the getMenuInflater() method. Later on in the book we’ll learn about the Java construct that allows us to “chain” Java commands together into a single line of code, as we see here as the method() attaches itself to the .method call.
As you learned previously, the R equates to the /res/ folder of our project, so R.menu.activity_main in this case is equivalent to (inflates to, if you will) the following complete file path reference: C:/Users/Walls/workspace/UI_Design/res/menu/activity_main.xml.
ADT also added a menu-related import statement at the top of our code to tell Android which UI code we would be using. We should specify android.view.Menu that forms the Menu Class foundation for our menu and android.app.Activity for the inflation methods that access the data structures defined in the /res/menu/activity_main.xml file containing our menu UI design coded in the XML format. In this case Eclipse added the import statement for us.
import android.view.Menu;
Figure 7-28 shows the code our New Project Android Application helper added to MainActivity.java.
Figure 7-28 . Creating our menu using the getMenuInflater() method in the Eclipse Java editing pane
Note that we have implemented our application’s UI and options menu using only a half-dozen lines of Java code. We have offloaded about 80% of the menu implementation coding to XML (30 lines of XML markup relative to 6 lines of Java code, or one-fifth Java, which is 20%), and we can continue to add features and fine-tune menu options inside the XML markup as well.
Running the Application in the Android Emulator
Let’s run our code and see our menu in action. Right-click on the UI_Design folder in the Package Explorer pane, and select: Run As Android Application. After the emulator loads, and you start up your application, the emulator should look like Figure 7-29.
Figure 7-29 . Running our UI Design application in the Android 4.1 emulator
As you can see, the Android phone has a prominent Menu button, second from the left (bottom row) in the emulator, which we can press to display our menu at the bottom of the screen. If you click the various buttons, they will highlight in blue and close the menu, which you can re-open again with the Menu button.
So, the default way an empty menu (no code yet completing its function) works is harmless to the application. This allows us to develop and test the way our menu looks via XML before we add in the Java logic to implement the actions that will be called when each button is pressed. This allows our UI designers to work separately from our programmers without breaking the application! Next we’ll code some basic programming logic to make our menu items functional.
Making the Menu Work
Let’s add our menu item implementations now. First, we need to give our RelativeLayout an ID, so that we can find it in our Java code.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android "
android:id="@+id/uilayout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
Now, we need to implement the onOptionsItemSelected() method, where we code the choices between our different menu item selections, and write the code that defines what they do in our application, if and when they are selected. Here is the Java code for the method we will write:
public boolean onOptionsItemSelected(MenuItem item) {
RelativeLayout bkgr = (RelativeLayout)findViewById(R.id.uilayout);
ImageView image = (ImageView)findViewById(R.id.imageView1);
switch (item.getItemId()) {
case R.id.buttonone:
image.setImageResource(R.drawable.image1);
return true;
case R.id.buttontwo:
image.setImageResource(R.drawable.image2);
return true;
case R.id.buttonthree:
bkgr.setBackgroundResource(R.color.background2);
return true;
case R.id.buttonfour:
bkgr.setBackgroundResource(R.color.background);
return true;
case R.id.buttonfive:
// The Alert Code For Next Section Goes Here!
return true;
default:
return super.onOptionsItemSelected(item);
}
}
This code is a bit more complex than our MenuInflater() code. At its core, it implements a switch structure. The switch is a Java iteration construct that says, “In the case of this, do that, and in the case of this, do that; otherwise, as a default, do this.” This type of code construct is perfect for the main Android menu, as it usually has only five or six items. Let’s type this code block into our MainActivity.java editing pane after the routine that inflates our new menu.
Once you are finished typing the new method into your MainActivity.java class, you will notice that there are three little red X icons in the left of the Java editing pane that signify that our code has a problem. Click on the first one as shown in Figure 7-30 to get Eclipse and ADT to tell you what is wrong and to give you some solutions to the problem.
Figure 7-30 . Debugging error flags inside Eclipse and adding Import statements needed
As you can see, Eclipse is telling us that we do not have the import statement that is required to run the method referenced in that line of code. Pretty Nifty! Double-click on the Import MenuItem (android.view) selection listed at the top of the pop-up, and Eclipse and ADT will write the import statement code for you. Do this for the next two warning flags as well to import the other packages (libraries) that are needed for RelativeLayouts and ImageView widget usage.
Figure 7-31 shows the MainActivity.java code in the Eclipse editor in context with our previous two code blocks once our Import statements are added and the editing area is “clean” with no errors or warnings showing. In the figure, the new code is boxed. We will cover the top import statements, then the outer onOptionsItemSelected() method, and then its inner switch statement and programming logic for each button inside of the case statement, and what it needs to do regarding the UI (switch images, set background colors, and so on).
Figure 7-31 . Java code to implement our menu functionality shown in the Eclipse IDE
First are the import statements for the Android classes that we are going to use in our onOptionsItemSelected() method (see the top box in Figure 7-31):
Remember that importing the class libraries that we are going to use in our Java code makes sure that these classes are in memory when Eclipse needs to use them during the compilation of our Java code.
Next, let’s examine our onOptionsItemSelected() code. First, we need to create references to our RelativeLayout and ImageView objects, so that we can operate on these objects. This way, we can adjust their resource values to change the image used in the UI and the background color used when the user selects our menu buttons’ image and background color change menu options.
The first line creates a RelativeLayout object called bkgr and sets it to the RelativeLayout that is assigned the ID uilayout via the findViewById() method. The second line creates an ImageView object called image and sets it to the ImageView that is assigned the ID imageView1 in the same way. These IDs can be seen in the /res/layout/ folder’s activity_main.xml file and corresponding tab, so you can check that everything matches.
Finally, we have the Java switch statement. It starts with switch(item.getItemId, which means “Decide between the following options (each case statement) based on the ID of the MenuObject that we named item. If nothing matches, just use the default action at the bottom of the statement decision tree list.” The case statements work as follows:
If none of the case statements match IDs passed over to them to operate on, then the default action is called (executed), which is to pass over to the onOptionsItemSelected() method of the superclass (in this case, to do nothing).
Now let’s Run As Android Application, and make sure that our code works! Shown below is a screen shot of the Android 4.1 emulator after the menu is brought up (twice) via the Menu Button (see right side of emulator), and the Image Two option and then the black background option were selected.
Adding Dialogs
An Android dialog can be created as part of an activity, and is presented in the form of a small, gray and white pop-up window that appears on top of the current activity’s UI. Android dims that UI so that it does not compete with the dialog box.
The Dialog class is used to create an interruption of your current activity to collect or relay information to your application’s end user. Examples of uses for dialogs include alert notifications, end-user option selection, information data collection, date selection, time selection, task or processing progress bar monitoring, and so on.
Using Custom Dialog Subclasses
Five custom subclasses of the android.app.Dialog class are provided as part of the Android API:
You can also subclass your own custom Dialog class (say, CustomDialog), so that it does exactly what you need it to do.
The general way to create a basic dialog within any given activity is via the onCreateDialog(int) method. Android uses this method to track the dialog created, which activity it belongs to, and its current state.
To display a dialog once it is created, you use the showDialog(int) method, specifying the number of the dialog you wish to display. To hide or dismiss a Dialog object, use the dismissDialog(int) method, and the Dialog object will be removed from memory and the application.
Here, we’ll take a closer look at the most often used (and the recommended) Dialog class: AlertDialog . Android provides an easy and powerful way to construct alert dialogs with many features.
Displaying an Alert Dialog
The AlertDialog class provides a lot of built-in dialog features, such as a title, user message, up to three buttons, and a list of selectable items. You can even use check boxes and radio buttons in your dialog.
The AlertDialog works its magic via a dialog builder that provides a ready-made dialog code structure for you to easily create complicated dialogs via the android.app.AlertDialog class.
As shown in the boxed areas of Figure 7-33, there are four main parts to adding our AlertDialog to our existing Android application.
Figure 7-33 . Java code for implementing our alert dialog builder in the Eclipse IDE
First, we add the import statements for the Android utilities we are going to leverage to provide our AlertDialog object:
import android.app.AlertDialog;
import android.content.DialogInterface;
Next, we create our AlertDialog.Builder object, which we name builder. This is a new (empty and initialized) AlertDialog.Builder object.
public boolean onOptionsItemSelected(MenuItem item) {
RelativeLayout bkgr = (RelativeLayout)findViewById(R.id.uilayout);
final ImageView image = (ImageView)findViewById(R.id.imageView1);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
To work with the image object inside the builder dialog object that we are constructing, we need to add the keyword final to our declaration of this object variable (you’ll see why in the next step). The final keyword is used for variables, methods, and classes. A final variable cannot be given a new value after it has been assigned one (although we can alter the variable object like any other object). A final method cannot be overridden. Also, a final class cannot be extended, and is thus, in a sense, protected from further programming modifications.
The preceding code basically says, “I want to declare an object named builder that is of the type AlertDialog.Builder, and I wish to set it equal to this new AlertDialog.Builder object that I am creating here. Therefore, please instantiate an empty AlertDialog.Builder object for me to define and fill with my own custom parameters.”
After this has been declared, builder exists as an empty AlertDialog ready to fill with our own custom parameters. OK, on to the fun part, and to the third and major part of our AlertDialog definition.
Here is the code to customize our dialog:
builder.setTitle("Pick an Image!")
.setMessage("Please Select Image One or Image Two:")
.setCancelable(false)
.setPositiveButton("IMAGE 1", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int id) {
image.setImageResource(R.drawable.image1);
}
})
.setNegativeButton("IMAGE 2", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
image.setImageResource(R.drawable.image2);
}
});
We work with the image object, which we know can’t be reassigned a value because it is final. This is to deal with situations where the event listener is used after the onOptionsItemSelected() method has terminated. In this case, a non final image variable would not be around to take a new assignment, whereas a final variable is frozen in memory for access at all times (of course, this may never happen, but Java was built this way just to be sure).
Notice in this block of code that sets our AlertDialog parameters (I am amazed that they did not offload AlertDialog parameters to an alert_dialog.xml file) that a new concept called method chaining is used. This allows a large number of parameters to be set without the builder object being explicitly typed before each dot-notation construct.
In method chaining, the first method is attached to its object with dot notation. In our example, it looks like this:
builder.setTitle("Pick an Image!")
The follow-up methods that set the other parameters are simply .setMessage(), .setCancelable(false), and so on.
I’ve formatted the preceding code for ease of reading. But to give you a little more grip on method chaining, the first three method calls could be rewritten as follows, illustrating the method chain:
builder.setTitle("Pick an Image!").setMessage("Please Select...").setCancelable(false)
Also note that between contiguous methods, there is no semicolon at the end of these parameter setting lines of code. Semicolons are required on only the last and final method call—in this case, after .setNegativeButton() to end the builder definition. This chaining allows programmers to write denser code, or to use fewer lines of code to accomplish more tasks. Pretty cool stuff.
Note In this case, the order of the chained methods doesn’t matter because each one returns an AlertDialog.Builder object with the new parameter set, alongside all the other parameters that have been set so far. In other cases, the order of chaining may matter. Android has been well designed to make chaining easy and convenient.
The code for setting the title, the message, and whether the Back button on the phone is able to cancel the dialog (in this case, it is not cancelable) is pretty straightforward here, so let’s go over what is happening inside each button.
You can have up to three buttons in an AlertDialog object. These buttons are hard coded into the Android operating system as follows:
This explains the setPositiveButton() and setNegativeButton() methods shown in the preceding code.
The convention in Android AlertDialogs is to use PositiveButton for one-button dialogs, PositiveButton and NegativeButton for two-button dialogs, and all three for three-button dialogs. The code inside the two buttons in our dialog is nearly identical, so let’s go over what is happening inside the first button, IMAGE 1.
.setPositiveButton("IMAGE 1", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int id) {
image.setImageResource(R.drawable.image1);
}
})
The setPositiveButton() method allows us to name the button IMAGE 1 and creates a new OnClickListener() implementation for the DialogInterface. Note that we declared android.content.DialogInterface in an import statement initially, and it is being used here to create a PositiveButton.
Inside the OnClickListener, we have a public method onClick(), which defines what will be done when the button is clicked. We pass onClick a dialog object of type DialogInterface and an integer ID value that represents which of the buttons was clicked or the numerical order of the button that was clicked—both of which are what OnClickListener wants to evaluate in the event the user clicks that button. Note that we will be getting into event listeners in much greater detail in Chapter 9.
Inside this onClick container is where our code goes to change our ImageView object to the appropriate image resource. Because we have already done that in the menu code, we can simply copy the image.setImageResource(R.drawable.image1) code from down in our switch construct for ButtonOne.
Finally, down inside of our switch statement, where before we had a placeholder comment, we can now display the dialog by calling the show() method of the builder object that we created earlier. This line of code could not be much simpler:
builder.show();
Whenever the fifth menu button is clicked, our dialog will be shown. We can select between the two images, which will then be set on our screen appropriately.
Now, right-click on your UI_Design folder, and select Run As Android Application to see your work. Figure 7-34 shows the dialog as it appears in the emulator after you click the SHOW ALERT button in the menu.
Figure 7-34 . Viewing our Pick an Image! alert dialog in the Android 4.1 emulator
Summary
With the exception of dialogs, Android allows us to put together our user interface, or UI, designs using XML markup instead of Java code, and to implement them using just a few dozen lines of code in many instances, such as when creating a system options menu. Allowing user interface design via XML markup allows applications designers to get one step closer to the application coding process.
In this chapter, we created an application that has all of the primary UI objects that can be used to construct an application:
In the next chapter, you will learn how to add graphics design elements, to provide even more visual new media user experiences within your Android applications. Right after that in Chapter 9 we'll revisit in detail the OnClick() event handler that you learned about briefly in the last section on AlertDialogs.
44.220.184.63