The UI design determines the usability of your application, which will ultimately determine its success and even its profitability if you are selling it.
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, menus, text fields, dialog boxes, system alerts, and similar widgets.
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.
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.
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.
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-graphics UIs, this is the class that you will need to use to gain the most control over the user experience.
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 with the Android operating environment.
There is a distinct work process to creating a successful multi-state 24-bit PNG image button, which will composite perfectly over background imagery using an 8-bit alpha channel.
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.
In case you're not familiar with some of the terms I used in the previous description, here are some brief definitions:
Compositing: The process of using layers to form a single new image out of more than one component part.
Alpha channel: That part of each layer that is transparent, and thus does not hold any image data passing through visible image data from other layers underneath it.
Anti-aliasing: The edge treatment that is used to make the edges of images within these transparency layers perfectly smooth when these edges are not perfectly square, which they rarely are.
The XML markup is a bit 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:
Pressed (for touchscreens, the pressed image will be shown when the finger is touching a button image on the screen)
Released or normal
Focused (in use or last touched)
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 main.xml file that goes in the /res/layout folder. You don't need to create this file now. In fact, when we get to that point in our example, you'll see that Eclipse creates this file for you automatically!
<?xml version="1.0" encoding="utf-8"?> <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 is the standard first line of every XML file that you code, and it will always say the same thing.
The second line defines a selector
tag and points to its XML schema, as you have seen in previous chapters. A selector
tag allows selection between several options. Inside the selector
tag, we nest three item
tags to show which drawable (bitmap) images to use for state_pressed=true, state_focused=true
, and the default or normal button state.
For this XML code to work, we must have three 24-bit bitmap PNG images in our project's /res/drawable folder named button1_pressed.png, button1_focused.png, and button1_normal.png.
Recall that each of the image file names must use only lowercase letters and numbers, and can also use the underscore character.
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).
The @
equates to your project's resources folder, /project/res/, so in this case, @drawable/button1_pressed
will equate to c:/projects/imagebuttons/res/drawable/button1_pressed.png in the Android compiler. The other item
tags follow the same format as the first one.
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 choose select File
Project name: Name the folder Chapter7.
Build Target: So our application runs on all of the popular Android operating system versions from 1.5 through 3.0, choose Android 1.5.
Application name: We'll call this application UI Examples.
Package name: Using the proper package name form, enter chapter.seven as the name.
Create Activity: Check this box and name the activity UserInterface.
Min SDK Version: Enter 3, to complement the build target choice.
Figure 7-1 shows the completed New Android Project dialog for our multistate image button example. Click Finish
after you've filled it in.
You now have an empty Eclipse project. Next, we'll create the button1.xml file so we can add the button state definition XML we created earlier.
Open the project tree on the left Package Explorer tab and expand the src folder by clicking the arrow. Then right-click the drawable folder and select New
In the New File dialog, ask Eclipse to create the file button1.xml in the Chapter7/res/drawable folder, as shown in Figure 7-3. 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.
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:
<?xml version="1.0" encoding="utf-8"?> <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>
After you've entered the XML, you'll notice that Eclipse shows that there are three errors in the markup relating to missing 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, as shown in Figure 7-4.
Figure 7.4. Eclipse shows us that our three image state buttons are missing via error flags in the IDE.
We have not put the three image button images in the /res/drawable folder where they belong. Eclipse is telling us that it does not see each file name that is referenced in the markup in the directory where it is supposed to be.
Once we add valid XML specifiers and code, the Eclipse error messages will disappear. But this does show 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.
Let's create the three button state files. I'm going to use Photoshop, but other good drawing tools can do the same thing. Also, these PNG images are provided with the book code examples, so you do not need to create them from scratch if you would rather not do that.
Just as in the examples in previous chapters, put the graphics on a transparency layer (indicated in Photoshop by a checkerboard pattern), so that you can overlay the image button on any background color or image you like. Figure 7-5 shows the completed images in Photoshop.
Figure 7.5. Our multistate image button images in Photoshop showing alpha channel transparency areas
Whenever you add new images or other assets to Eclipse, you need to tell Eclipse about the new assets. To do this, right-click the top-level project folder and select Refresh
, as shown in Figure 7-6. You'll notice that the red errors no longer appear in the file.
There is also a deeper level of refreshing called validating, which will go into even deeper depths in your code and image assets. If the red error marks do not disappear, simply right-click the Chapter7 top-level folder again and choose the Validate option.
Next, open the res folder and right-click the main.xml file to open it for editing. Notice that our image button source files now appear in the Package Explorer pane.
We need to replace the default text tag in the 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:paddingTop="5px"> </ImageButton>
Figure 7-7 shows the IDE at this point.
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 have 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 .png for graphic files. We add 5 pixels of padding to the top of the image, just to practice using padding values.
Figure 7-8 shows how our UI Examples app looks when run in the Android 1.5 emulator (right-click Chapter7 and select Run As
When you click the image button, it changes color and uses the standard orange background to highlight the button being clicked.
Since we want just the image to be the button (which is why we used transparency and an alpha channel in Photoshop), we will set a background color, or transparency, next.
We do not want to use the default Android button background. We want the background to be transparent so we can use this ImageButton
to put an image on top of a button and its text, as well as being able to make the image 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 or set the background color to 100% transparent 32-bit alpha channel with the #00000000
setting (which means zero red, zero green, zero blue, zero alpha). This is similar to setting HTML color with the pattern #RRGGBBAA
. That is the most elegant solution, so let's implement that now.
We'll do this in a new way, so that you learn how to use another cool Eclipse function that helps you design your UI widgets and layouts. I think this is a really slick trick, and it was pretty difficult to figure out. As such, this is fairly advanced. Stick with it, though, and you won't be disappointed.
Click the main.xml tab at the top of your screen, and then click the Layout tab at the bottom of the pane that shows your XML for the ImageButton
(see Figure 7-9). 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 visual 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.9. Using the Eclipse visual layout editor and Properties tab to set your image background to transparent
An even cooler tab is the Properties tab at the bottom of the screen. This tab shows all of the properties assigned or available to the UI element tag that you have selected in the layout view. Click the button element, and a red line will surround the button, 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. Eclipse then provides a button to search for a file to use as a background image.
Since we are just going to set the background to transparent, we do not need to use this button for the example. Instead, type the transparency value #00000000
into the field next to Background in the Properties tab, as shown in Figure 7-9. Then click somewhere else in the IDE. The value will be accepted and the results displayed in the Layout tab!
That finishes up our custom image button. Next, let's look at how to add text to your app's UI.
Besides buttons, another common UI element is text. Android provides the TextView
class to implement text in a UI.
Since we are using the visual layout editor in Eclipse, let's continue to explore its functionality. Click the left header bar called Layouts to close the layouts selection view, leaving only the Views (remember widgets are really views) pane open. Clicking these headers will toggle them open and shut at any time (try it now if you don't believe me).
Next, click the scrollbar (gray, with a tiny arrow) until you see the TextView
widget. Select and drag (and drop) it into the Layout view window under the ImageButton
. Our TextView
is now in the UI view and is ready to customize by using the Properties tab at the bottom 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 gold to match the ImageButton
default image (an RGB value of #CCCC77
will work well; this is a hexadecimal numeric representation of a 24-bit value). Figure 7-10 shows the Eclipse IDE at this point.
Figure 7.10. Using the Eclipse visual layout editor to add and configure a TextView widget in the main.xml file
Finally, we'll set a dpi value for padding, so that there is some space around our TextView
. Scroll to the Padding properties in the Properties tab at the bottom of your Eclipse IDE, and type in 12dip, as shown in Figure 7-11. Then click another field, and you will see the text space itself out.
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 image files named image1.png and image2.png into your Chapter7/res/drawable folder.
Right-click the Chapter7 folder in the Package Explorer pane and refresh the project.
Now, let's add an ImageView
tag to our XML. To do this, drag the ImageView
from the Views list on the left and drop it under the TextView
. This gives us a LinearLayoutViewGroup
containing ImageButton, TextView
, and ImageView
tags.
Next, in the Properties tab below the visual editing window, click the Src (for Source) property, and then click the button on the right with three dots (ellipsis) to open the Reference Chooser dialog. Open the Drawable folder and select image1 for our ImageView
source imagery, as shown in Figure 7-12. Click the OK button to close the dialog.
Figure 7.12. Choosing our image resource via the Reference Chooser dialog, accessed by clicking the ellipsis in the Src field in the Properties tab
In your visual layout tab, you will now see the image and how its transparency area composites smoothly with the black background color.
Later, when we add a menu to our app, we will change the background color to white to show how this image transparency can help with UI compositing over different background colors or imagery.
So now in the next screen, you will see our ImageButton, TextView
, and ImageView
with enough screen area to hold a bottom menu of icons. Also note that we used the drop-down at the top to change our orientation to Portrait mode, as shown in Figure 7-13. This orientation fits our application design better. We'll add menus in the next section.
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 is a bit different for ease of use, and is an actual physical button called Menu on Android phones.
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 square icons that can be easily touched to control 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 in the chapter), so that everything we cover in this chapter ties together.
As you might have guessed, you set up your entire menu structure in an XML file. The menu XML file goes in a /res subfolder named menu, as required by Android. So, first create a folder under the /res folder called menu. Next, right-click the Chapter7 project folder, select New
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/buttonone" android:icon="@drawable/image1icon" android:title="@string/showimage1" /> <item android:id="@+id/buttontwo" android:icon="@drawable/image2icon" android:title="@string/showimage2" /> <item android:id="@+id/buttonthree" android:icon="@drawable/menu3icon" android:title="@string/showwhite" /> <item android:id="@+id/buttonfour" android:icon="@drawable/menu4icon" android:title="@string/showblack" /> <item android:id="@+id/buttonfive" android:icon="@drawable/menu5icon" android:title="@string/showalert" /> </menu>
The menu
XML tag is fairly straightforward. It simply declares the location of its XML schema definition and nested item
tags that specify attributes for each menu item to be added. The Android menu holds five items comfortably, and it can hold more than that via a sixth item that drops down a submenu. Most Android applications use five or fewer menu items.
Each of the item
tags has the following three attributes:
The android:id
attribute allows the item
tag to be given a name and referenced in your Java code.
The android:icon
attribute is the location of the graphic file that will be used for the menu icon. In the first item, it is located in the Chapter7/res/drawable folder and named image1icon.png, shown in Android shorthand as @drawable/image1icon.
The android:title
attribute is the title or label for the menu button. The title is in the strings.xml file, where text constants are defined (we'll do that next).
Figure 7-14 shows the completed Chapter7/res/menu/menuname.xml file. The figure also shows the five icon files (image1icon, image2icon, menu3icon, menu4icon, and menu5icon) placed in the /res/drawable folder, where Android looks for image files for the application. The images are all 24-bit PNG files with transparency, as you will see when they appear on our menu's buttons.
Next, we'll go into the strings.xml file in the /res/values folder (under the menu folder in the Package Explorer pane) to edit our application's string constants. We'll add the text for our five menu items. Follow these steps to add the five string values specified in our mainmenu.xml file:
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-15.
Click the Resources tab at the bottom of the pane to see a visual representation of the values in the strings.xml file.
Remember that if you want to see the XML, click the strings.xml tab next to it. 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!
Click the Add button to bring up the dialog shown in Figure 7-16. Select String and click OK to add a string to our strings.xml file.
In the area on the right, in the Name field, enter showimage1
. In the Value field, enter IMAGE ONE. Click the Add button to add this string value to the strings.xml file.
Repeat steps 3 and 4 to add four more string values with the following names and values:
showimage2, IMAGE TWO
showwhite, USE WHITE
showblack, USE BLACK
showalert, SHOW ALERT
Set our default black background color of #000000
as a Color
object, as shown in Figure 7-17.
Add a white background called background2
, using a value of #FFFFFF
.
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 described in an XML file and populating an object that can be accessed and used in Java. In this case, it is our mainmenu
object, which contains five menu selection buttons, their icon resources, and the text captions.
Here is the Java code to add to our UserInterface.java file:
public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.mainmenu, menu); return true; }
Android has a dedicated Java object for inflating XML code constructs into an object-based format for use with Java. This is precisely what you are seeing here inside the onCreateOptionsMenu()
method, which uses the inflate()
method and the R.menu.mainmenu path to our mainmenu.xml file. It creates the inflaterMenuInflater
object, which contains our inflated menu objects. The R equates to the res folder of our project, so R.menu.mainmenu is equivalent to c:/Projects/Chapter7/res/menu/mainmenu.xml.
We also added two import
statements at the top of our code to tell Android which UI code we would be using. We specify android.view.Menu
and android.view.MenuInflater
, which form the foundation for our menu and its inflation from the XML format.
import android.view.Menu; import android.view.MenuInflater;
Figure 7-18 shows the code added to UserInterface.java.
Note that we have implemented our application's options menu in little more than a half-dozen lines of Java code. We have offloaded about 80% of the menu implementation coding to XML, and we can continue to add features and fine-tune menu options inside the XML markup as well.
Let's run our code and see our menu in action. Right-click the Chapter7 folder in the Package Explorer pane and select Run As...
As you can see, the Android phone has a prominent Menu button, which we can press to display our menu at the bottom of the screen. You can see the translucency of the menu. If you look closely at the first button, you will see the bottom of the ImageView
behind the menu. If you click the various buttons, they will highlight in orange and close the menu, which you can reopen with the Menu button.
So, the default way an empty menu works is harmless to the application. It 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.
Let's add our menu item implementations now. First, we need to give our LinearLayout
an ID, so that we can find it in our code.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/uilayout"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
Now, we need to implement the onOptionsItemSelected()
method, where we code the choices between our different menu item selections and what they do in our application if and when they are selected.
public boolean onOptionsItemSelected(MenuItem item) { LinearLayout bkgr = (LinearLayout)findViewById(R.id.uilayout); ImageView image = (ImageView)findViewById(R.id.ImageView01); 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 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.
Figure 7-20 shows the UserInterface.java code in the Eclipse editor in context with our previous two code blocks. 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 case
statement and what it needs to do in the UI (switch images, background colors, and so on).
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-20):
Since we reference MenuItem
in our onOptionsItemSelected()
method, we need to import android.view.MenuItem
.
Since we are going to switch image resources in our ImageView
UI object, we also need to import android.widget.ImageView
.
Since we are going to change our LinearLayout
background color from black to white, we need to import android.widget.LinearLayout
as well.
Remember that importing the class libraries that we are going to use in our Java code makes sure they 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 LinearLayout
and ImageView
objects, so that we can operate on these objects. This way, we can adjust their resource values to change our menu buttons' image and background color.
The first line creates a LinearLayout
object called bkgr
and sets it to the LinearLayout
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 ImageView01
in the same way. These IDs can be seen in the main.xml file and tab, so you can check that everything matches up.
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:
The first case
statement says, "In the case of the itemMenuItem
with an ID of buttonone
being passed, please set the imageImageView
object's image resource to the 24-bit PNG image called image1 in the /drawable folder using the setImageResource()
method."
The second case
statement says, "In the case of the itemMenuItem
with an ID of buttontwo
being passed over, please set the imageImageView
object's image resource to the 24-bit PNG image called image2 in the /drawable folder using the setImageResource()
method."
The third case
statement says, "In the case of the itemMenuItem
with an ID of buttonthree
being passed over, please set the bkgrLinearLayout
object's background resource to the color resource called background2 in the /values/strings.xml resource using the setBackgroundResource()
method."
The fourth case
statement says, "In the case of the itemMenuItem
with an ID of buttonfour
being passed over, please set the bkgrLinearLayout
object's background resource to the color resource called background in the /values/strings.xml resource using the setBackgroundResource()
method."
The fifth case
is left open for our next section, and thus the button does nothing at this point.
If none of the case
statements match IDs passed over to operate on, then the default
action is made, which is to pass over to the onOptionsItemSelected()
method of the superclass.
An Android dialog is always created as part of an activity, and is presented in the form of a small, gray 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 in order 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.
Four custom subclasses of the Dialog
class are provided as part of the Android API:
AlertDialog
ProgressDialog
DatePickerDialog
TimePickerDialog
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.
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 list.
The AlertDialog
works its magic via a dialog builder that provides a ready-made dialog code structure for you to create complicated dialogs via the AlertDialog.Builder
class.
As shown in the boxed areas of Figure 7-21, there are four main parts to adding our AlertDialog
to our existing Android application.
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) { LinearLayout bkgr = (LinearLayout)findViewById(R.id.uilayout);final
ImageView image = (ImageView)findViewById(R.id.ImageView01);AlertDialog.Builder builder = new AlertDialog.Builder(this);
In order 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 the third and major part of 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-finalimage
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-on 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 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.
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 matters. 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 here 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. onClick()
is passed 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.
Inside this onClick
container is where our code goes to change our ImageView
object to the appropriate image resource. Since 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 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 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 your Chapter7 folder and select Run As...
With the exception of dialogs, Android allows us to put together our designs using XML, and to implement them with just a half-dozen lines of code is some instances, such as when creating a system options menu. This allows designers to get one step closer to the 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:
ImageButton
s allow us to create custom UI elements.
TextView
and ImageView
objects allow us to put relevant information on the screen.
Menu
items allow us to use the Android Menu button to control our application.
Alert dialogs interface with our users to gather information or inform about decisions.
In the next chapter, you will learn how to add graphics to provide even more new media user experiences in your Android applications.
98.82.120.188