04 user interfaces


Published on

Part IV of Android Tutorial.

Published in: Technology, Art & Photos
  • Be the first to comment

  • Be the first to like this

No Downloads
Total Views
On Slideshare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

04 user interfaces

  1. 1. User Interfaces.In an Android application, the user interface is built using View and ViewGroup objects. There aremany types of views and view groups, each of which is a descendant of the View class.View objects are the basic units of user interface expression on the Android platform. The View classserves as the base for subclasses called "widgets," which offer fully implemented UI objects, like textfields and buttons. The ViewGroup class serves as the base for subclasses called "layouts," whichoffer different kinds of layout architecture, like linear, tabular and relative.A View object is a data structure whose properties store the layout parameters and content for aspecific rectangular area of the screen. A View object handles its own measurement, layout, drawing,focus change, scrolling, and key/gesture interactions for the rectangular area of the screen in which itresides. As an object in the user interface, a View is also a point of interaction for the user and thereceiver of the interaction events.View Hierarchy On the Android platform, you define an Activitys UI using a hierarchy of View and ViewGroup nodes, as shown in the diagram below. This hierarchy tree can be as simple or complex as you need it to be, and you can build it up using Androids set of predefined widgets and layouts, or with custom Views that you create yourself. In order to attach the view hierarchy tree to the screen for rendering, your Activity must call the setContentView() methodand pass a reference to the root node object. The Android system receives this reference and uses itto invalidate, measure, and draw the tree. The root node of the hierarchy requests that its child nodesdraw themselves — in turn, each view group node is responsible for calling upon each of its own childviews to draw themselves. The children may request a size and location within the parent, but theparent object has the final decision on where how big each child can be. Android parses the elementsof your layout in-order (from the top of the hierarchy tree), instantiating the Views and adding them totheir parent(s). Because these are drawn in-order, if there are elements that overlap positions, the lastone to be drawn will lie on top of others previously drawn to that space.For a more detailed discussion on how view hierarchies are measured and drawn, read How AndroidDraws Views.LayoutThe most common way to define your layout and express the view hierarchy is with an XML layout file.XML offers a human-readable structure for the layout, much like HTML. Each element in XML is either
  2. 2. a View or ViewGroup object (or descendant thereof). View objects are leaves in the tree, ViewGroupobjects are branches in the tree (see the View Hierarchy figure above).The name of an XML element is respective to the Java class that it represents. So a <TextView>element creates a TextView in your UI, and a <LinearLayout> element creates a LinearLayout viewgroup. When you load a layout resource, the Android system initializes these run-time objects,corresponding to the elements in your layout.For example, a simple vertical layout with a text view and a button looks like this: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello, I am a TextView" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello, I am a Button" /> </LinearLayout>Notice that the LinearLayout element contains both the TextView and the Button. You can nest anotherLinearLayout (or other type of view group) inside here, to lengthen the view hierarchy and create amore complex layout.For more on building a UI layout, read Declaring Layout.Tip: You can also draw View and ViewGroups objects in Java code, using the addView(View) methodsto dynamically insert new View and ViewGroup objects.There are a variety of ways in which you can layout your views. Using more and different kinds of viewgroups, you can structure child views and view groups in an infinite number of ways. Some pre-definedview groups offered by Android (called layouts) include LinearLayout, RelativeLayout, TableLayout,GridLayout and others. Each offers a unique set of layout parameters that are used to define thepositions of child views and layout structure.To learn about some of the different kinds of view groups used for a layout, read Common LayoutObjects.WidgetsA widget is a View object that serves as an interface for interaction with the user. Android provides aset of fully implemented widgets, like buttons, checkboxes, and text-entry fields, so you can quickly
  3. 3. build your UI. Some widgets provided by Android are more complex, like a date picker, a clock, and zoom controls. But youre not limited to the kinds of widgets provided by the Android platform. If youd like to do something more customized and create your own actionable elements, you can, by defining your own View object or by extending and combining existing widgets. Read more in Building Custom Components. For a list of the widgets provided by Android, see the android.widget package. UI Events Once youve added some Views/widgets to the UI, you probably want to know about the users interaction with them, so you can perform actions. To be informed of UI events, you need to do one of two things: Define an event listener and register it with the View. More often than not, this is how youll listen for events. The View class contains a collection of nested interfaces named On<something>Listener, each with a callback method called On<something>(). For example, View.OnClickListener (for handling "clicks" on a View), View.OnTouchListener (for handling touch screen events in a View), and View.OnKeyListener (for handling device key presses within a View). So if you want your View to be notified when it is "clicked" (such as when a button is selected), implement OnClickListener and define its onClick() callback method (where you perform the action upon click), and register it to the View with setOnClickListener(). Override an existing callback method for the View. This is what you should do when youve implemented your own View class and want to listen for specific events that occur within it. Example events you can handle include when the screen is touched (onTouchEvent()), when the trackball is moved (onTrackballEvent()), or when a key on the device is pressed (onKeyDown()). This allows you to define the default behavior for each event inside your custom View and determine whether the event should be passed on to some other child View. Again, these are callbacks to the View class, so your only chance to define them is when you build a custom component. Continue reading about handling user interaction with Views in the Handling UI Events document. Menus Application menus are another important part of an applications UI. Menus offers a reliable interface that reveals application functions and settings. The most common application menu is revealed by pressing the MENU key on the device. However, you can also add Context Menus, which may be revealed when the user presses and holds down on an item. Menus are also structured using a View hierarchy, but you dont define this structure yourself. Instead, you define the onCreateOptionsMenu() or onCreateContextMenu() callback methods for your Activity and declare the items that you want to include in your menu. At the appropriate time, Android will automatically create the necessary View hierarchy for the menu and draw each of your menu items in it.
  4. 4. Menus also handle their own events, so theres no need to register event listeners on the items in your menu. When an item in your menu is selected, the onOptionsItemSelected() or onContextItemSelected() method will be called by the framework. And just like your application layout, you have the option to declare the items for you menu in an XML file. Read Creating Menus to learn more. Advanced Topics Once youve grappled the fundamentals of creating a user interface, you can explore some advanced features for creating a more complex application interface. Adapters Sometimes youll want to populate a view group with some information that cant be hard-coded, instead, you want to bind your view to an external source of data. To do this, you use an AdapterView as your view group and each child View is initialized and populated with data from the Adapter. The AdapterView object is an implementation of ViewGroup that determines its child views based on a given Adapter object. The Adapter acts like a courier between your data source (perhaps an array of external strings) and the AdapterView, which displays it. There are several implementations of the Adapter class, for specific tasks, such as the CursorAdapter for reading database data from a Cursor, or an ArrayAdapter for reading from an arbitrary array. To learn more about using an Adapter to populate your views, read Binding to Data with AdapterView. Styles and Themes Perhaps youre not satisfied with the look of the standard widgets. To revise them, you can create some of your own styles and themes. A style is a set of one or more formatting attributes that you can apply as a unit to individual elements in your layout. For example, you could define a style that specifies a certain text size and color, then apply it to only specific View elements. A theme is a set of one or more formatting attributes that you can apply as a unit to all activities in an application, or just a single activity. For example, you could define a theme that sets specific colors for the window frame and the panel background, and sets text sizes and colors for menus. This theme can then be applied to specific activities or the entire application. Styles and themes are resources. Android provides some default style and theme resources that you can use, or you can declare your own custom style and theme resources. Learn more about using styles and themes in the Applying Styles and Themes document.
  5. 5. Declaring Layout. Your layout is the architecture for the user interface in an Activity. It defines the layout structure and holds all the elements that appear to the user. You can declare your layout in two ways: Declare UI elements in XML. Android provides a straightforward XML vocabulary that corresponds to the View classes and subclasses, such as those for widgets and layouts. Instantiate layout elements at runtime. Your application can create View and ViewGroup objects (and manipulate their properties) programmatically. The Android framework gives you the flexibility to use either or both of these methods for declaring and managing your applications UI. For example, you could declare your applications default layouts in XML, including the screen elements that will appear in them and their properties. You could then add code in your application that would modify the state of the screen objects, including those declared in XML, at run time. The ADT Plugin for Eclipse offers a layout preview of your XML — with the XML file opened, select the Layout tab. You should also try the Hierarchy Viewer tool, for debugging layouts — it reveals layout property values, draws wireframes with padding/margin indicators, and full rendered views while you debug on the emulator or device. The layoutopt tool lets you quickly analyze your layouts and hierarchies for inefficiencies or other problems. The advantage to declaring your UI in XML is that it enables you to better separate the presentation of your application from the code that controls its behavior. Your UI descriptions are external to your application code, which means that you can modify or adapt it without having to modify your source code and recompile. For example, you can create XML layouts for different screen orientations, different device screen sizes, and different languages. Additionally, declaring the layout in XML makes it easier to visualize the structure of your UI, so its easier to debug problems. As such, this document focuses on teaching you how to declare your layout in XML. If youre interested in instantiating View objects at runtime, refer to the ViewGroup and View class references. In general, the XML vocabulary for declaring UI elements closely follows the structure and naming of the classes and methods, where element names correspond to class names and attribute names correspond to methods. In fact, the correspondence is often so direct that you can guess what XML attribute corresponds to a class method, or guess what class corresponds to a given xml element. However, note that not all vocabulary is identical. In some cases, there are slight naming differences. For example, the EditText element has a text attribute that corresponds to EditText.setText(). Tip: Learn more about different layout types in Common Layout Objects. There are also a collection of tutorials on building various layouts in the Hello Views tutorial guide. Write the XML
  6. 6. For your convenience, the API reference documentation for UI related classes lists the available XMLattributes that correspond to the class methods, including inherited attributes.To learn more about the available XML elements and attributes, as well as the format of the XML file,see Layout Resources.Using Androids XML vocabulary, you can quickly design UI layouts and the screen elements theycontain, in the same way you create web pages in HTML — with a series of nested elements.Each layout file must contain exactly one root element, which must be a View or ViewGroup object.Once youve defined the root element, you can add additional layout objects or widgets as childelements to gradually build a View hierarchy that defines your layout. For example, heres an XMLlayout that uses a vertical LinearLayout to hold a TextView and a Button: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello, I am a TextView" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello, I am a Button" /> </LinearLayout>After youve declared your layout in XML, save the file with the .xml extension, in your Android projectsres/layout/ directory, so it will properly compile.Well discuss each of the attributes shown here a little later.Load the XML ResourceWhen you compile your application, each XML layout file is compiled into a View resource. You shouldload the layout resource from your application code, in your Activity.onCreate() callbackimplementation. Do so by calling setContentView(), passing it the reference to your layout resource inthe form of: R.layout.layout_file_name For example, if your XML layout is saved as main_layout.xml,you would load it for your Activity like so: public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main_layout); }
  7. 7. The onCreate() callback method in your Activity is called by the Android framework when your Activity is launched (see the discussion about lifecycles, in the Activities document). Attributes Every View and ViewGroup object supports their own variety of XML attributes. Some attributes are specific to a View object (for example, TextView supports the textSize attribute), but these attributes are also inherited by any View objects that may extend this class. Some are common to all View objects, because they are inherited from the root View class (like the id attribute). And, other attributes are considered "layout parameters," which are attributes that describe certain layout orientations of the View object, as defined by that objects parent ViewGroup object. ID Any View object may have an integer ID associated with it, to uniquely identify the View within the tree. When the application is compiled, this ID is referenced as an integer, but the ID is typically assigned in the layout XML file as a string, in the id attribute. This is an XML attribute common to all View objects (defined by the View class) and you will use it very often. The syntax for an ID, inside an XML tag is: android:id="@+id/my_button" The at-symbol (@) at the beginning of the string indicates that the XML parser should parse and expand the rest of the ID string and identify it as an ID resource. The plus-symbol (+) means that this is a new resource name that must be created and added to our resources (in the R.java file). There are a number of other ID resources that are offered by the Android framework. When referencing an Android resource ID, you do not need the plus-symbol, but must add the android package namespace, like so: android:id="@android:id/empty" With the android package namespace in place, were now referencing an ID from the android.R resources class, rather than the local resources class. In order to create views and reference them from the application, a common pattern is to:1. Define a view/widget in the layout file and assign it a unique ID: <Button android:id="@+id/my_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/my_button_text"/>2. Then create an instance of the view object and capture it from the layout (typically in the onCreate() method):
  8. 8. Button myButton = (Button) findViewById(R.id.my_button); Defining IDs for view objects is important when creating a RelativeLayout. In a relative layout, sibling views can define their layout relative to another sibling view, which is referenced by the unique ID. An ID need not be unique throughout the entire tree, but it should be unique within the part of the tree you are searching (which may often be the entire tree, so its best to be completely unique when possible). Layout Parameters XML layout attributes named layout_something define layout parameters for the View that are appropriate for the ViewGroup in which it resides. Every ViewGroup class implements a nested class that extends ViewGroup.LayoutParams. This subclass contains property types that define the size and position for each child view, as appropriate for the view group. As you can see in figure 1, the parent view group defines layout parameters for each child view (including the child view group). Figure 1. Visualization of a view hierarchy with layout parameters associated with each view. Note that every LayoutParams subclass has its own syntax for setting values. Each child element must define LayoutParams that are appropriate for its parent, though it may also define different LayoutParams for its own children. All view groups include a width and height (layout_width and layout_height), and each view is required to define them. Many LayoutParams also include optional margins and borders. You can specify width and height with exact measurements, though you probably wont want to do this often. More often, you will use one of these constants to set the width or height: wrap_content tells your view to size itself to the dimensions required by its content
  9. 9.  fill_parent (renamed match_parent in API Level 8) tells your view to become as big as its parent view group will allow. In general, specifying a layout width and height using absolute units such as pixels is not recommended. Instead, using relative measurements such as density-independent pixel units (dp), wrap_content, or fill_parent, is a better approach, because it helps ensure that your application will display properly across a variety of device screen sizes. The accepted measurement types are defined in the Available Resources document. Layout Position The geometry of a view is that of a rectangle. A view has a location, expressed as a pair of left and top coordinates, and two dimensions, expressed as a width and a height. The unit for location and dimensions is the pixel. It is possible to retrieve the location of a view by invoking the methods getLeft() and getTop(). The former returns the left, or X, coordinate of the rectangle representing the view. The latter returns the top, or Y, coordinate of the rectangle representing the view. These methods both return the location of the view relative to its parent. For instance, when getLeft() returns 20, that means the view is located 20 pixels to the right of the left edge of its direct parent. In addition, several convenience methods are offered to avoid unnecessary computations, namely getRight() and getBottom(). These methods return the coordinates of the right and bottom edges of the rectangle representing the view. For instance, calling getRight() is similar to the following computation: getLeft() + getWidth(). Size, Padding and Margins The size of a view is expressed with a width and a height. A view actually possess two pairs of width and height values. The first pair is known as measured width and measured height. These dimensions define how big a view wants to be within its parent. The measured dimensions can be obtained by calling getMeasuredWidth() and getMeasuredHeight(). The second pair is simply known as width and height, or sometimes drawing width and drawing height. These dimensions define the actual size of the view on screen, at drawing time and after layout. These values may, but do not have to, be different from the measured width and height. The width and height can be obtained by calling getWidth() and getHeight(). To measure its dimensions, a view takes into account its padding. The padding is expressed in pixels for the left, top, right and bottom parts of the view. Padding can be used to offset the content of the view by a specific amount of pixels. For instance, a left padding of 2 will push the views content by 2 pixels to the right of the left edge. Padding can be set using the setPadding(int, int, int, int) method and queried by calling getPaddingLeft(), getPaddingTop(), getPaddingRight() and getPaddingBottom().
  10. 10. Even though a view can define a padding, it does not provide any support for margins. However, viewgroups provide such a support. Refer to ViewGroup and ViewGroup.MarginLayoutParams for furtherinformation.For more information about dimensions, see Dimension Values.Creating Menus.Menus are an important part of an activitys user interface, which provide users a familiar way toperform actions. Android offers a simple framework for you to add standard menus to your application.There are three types of application menus:Options Menu The primary collection of menu items for an activity, which appears when the user touches the MENU button. When your application is running on Android 3.0 or later, you can provide quick access to select menu items by placing them directly in the Action Bar, as "action items."Context Menu A floating list of menu items that appears when the user touches and holds a view thats registered to provide a context menu.Submenu A floating list of menu items that appears when the user touches a menu item that contains a nested menu.This document shows you how to create each type of menu, using XML to define the content of themenu and callback methods in your activity to respond when the user selects an item.Creating a Menu ResourceInstead of instantiating a Menu in your application code, you should define a menu and all its items inan XML menu resource, then inflate the menu resource (load it as a programmable object) in yourapplication code. Using a menu resource to define your menu is a good practice because it separatesthe content for the menu from your application code. Its also easier to visualize the structure andcontent of a menu in XML.To create a menu resource, create an XML file inside your projects res/menu/ directory and build themenu with the following elements:<menu> Defines a Menu, which is a container for menu items. A <menu> element must be the root node for the file and can hold one or more <item> and <group> elements.<item>
  11. 11. Creates a MenuItem, which represents a single item in a menu. This element may contain a nested <menu> element in order to create a submenu.<group> An optional, invisible container for <item> elements. It allows you to categorize menu items so they share properties such as active state and visibility. See the section about Menu groups.Heres an example menu named game_menu.xml: <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/new_game" android:icon="@drawable/ic_new_game" android:title="@string/new_game" /> <item android:id="@+id/help" android:icon="@drawable/ic_help" android:title="@string/help" /> </menu>This example defines a menu with two items. Each item includes the attributes:android:id A resource ID thats unique to the item, which allows the application can recognize the item when the user selects it.android:icon A reference to a drawable to use as the items icon.android:title A reference to a string to use as the items title.There are many more attributes you can include in an <item>, including some that specify how theitem may appear in the Action Bar. For more information about the XML syntax and attributes for amenu resource, see the Menu Resource reference.Inflating a Menu ResourceFrom your application code, you can inflate a menu resource (convert the XML resource into aprogrammable object) using MenuInflater.inflate(). For example, the following code inflates thegame_menu.xml file defined above, during the onCreateOptionsMenu() callback method, to use themenu as the activitys Options Menu: @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater();
  12. 12. inflater.inflate(R.menu.game_menu, menu); return true; }The getMenuInflater() method returns a MenuInflater for the activity. With this object, you can callinflate(), which inflates a menu resource into a Menu object. In this example, the menu resourcedefined by game_menu.xml is inflated into the Menu that was passed into onCreateOptionsMenu().(This callback method for the Options Menu is discussed more in the next section.)Creating an Options MenuFigure 1. Screenshot of the Options Menu in the Browser. The Options Menu is where you should include basic activity actions and necessary navigation items (for example, a button to open the application settings). Items in the Options Menu are accessible in two distinct ways: the MENU button or in the Action Bar (on devices running Android 3.0 or higher). When running on a device with Android 2.3 and lower, the Options Menu appears at the bottom of the screen, as shown in figure 1. When opened, the first visible portion of the Options Menu is the icon menu. It holds the first six menu items. If you add more than six items to the Options Menu, Android places the sixth item and those after it into the overflow menu, which the user can open by touching the "More" menu item. On Android 3.0 and higher, items from the Options Menu is placed in the Action Bar, which appears at the top of the activity in place of the traditional title bar. By default all items from the Options Menu areplaced in the overflow menu, which the user can open by touching the menu icon on the right side ofthe Action Bar. However, you can place select menu items directly in the Action Bar as "action items,"for instant access, as shown in figure 2.When the Android system creates the Options Menu for the first time, it calls your activitysonCreateOptionsMenu() method. Override this method in your activity and populate the Menu that ispassed into the method, Menu by inflating a menu resource as described above in Inflating a MenuResource. For example: @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.game_menu, menu); return true; }
  13. 13. Figure 2. Screenshot of the Action Bar in the Email application, with two action items from the OptionsMenu, plus the overflow menu.You can also populate the menu in code, using add() to add items to the Menu. Note: On Android 2.3 and lower, the system calls onCreateOptionsMenu() to create the Options Menu when the user opens it for the first time, but on Android 3.0 and greater, the system creates it as soon as the activity is created, in order to populate the Action Bar.Responding to user actionWhen the user selects a menu item from the Options Menu (including action items in the Action Bar),the system calls your activitys onOptionsItemSelected() method. This method passes the MenuItemthat the user selected. You can identify the menu item by calling getItemId(), which returns the uniqueID for the menu item (defined by the android:id attribute in the menu resource or with an integer givento the add() method). You can match this ID against known menu items and perform the appropriateaction. For example: @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle item selection switch (item.getItemId()) { case R.id.new_game: newGame(); return true; case R.id.help: showHelp(); return true; default: return super.onOptionsItemSelected(item); } }In this example, getItemId() queries the ID for the selected menu item and the switch statementcompares the ID against the resource IDs that were assigned to menu items in the XML resource.When a switch case successfully handles the menu item, it returns true to indicate that the itemselection was handled. Otherwise, the default statement passes the menu item to the super class, incase it can handle the item selected. (If youve directly extended the Activity class, then the superclass returns false, but its a good practice to pass unhandled menu items to the super class instead ofdirectly returning false.)Additionally, Android 3.0 adds the ability for you to define the on-click behavior for a menu item in themenu resource XML, using the android:onClick attribute. So you dont need to implementonOptionsItemSelected(). Using the android:onClick attribute, you can specify a method to call whenthe user selects the menu item. Your activity must then implement the method specified in the
  14. 14. android:onClick attribute so that it accepts a single MenuItem parameter—when the system calls thismethod, it passes the menu item selected. Tip: If your application contains multiple activities and some of them provide the same Options Menu, consider creating an activity that implements nothing except the onCreateOptionsMenu() and onOptionsItemSelected() methods. Then extend this class for each activity that should share the same Options Menu. This way, you have to manage only one set of code for handling menu actions and each descendant class inherits the menu behaviors. If you want to add menu items to one of your descendant activities, override onCreateOptionsMenu() in that activity. Call super.onCreateOptionsMenu(menu) so the original menu items are created, then add new menu items with menu.add(). You can also override the super classs behavior for individual menu items.Changing menu items at runtimeOnce the activity is created, the onCreateOptionsMenu() method is called only once, as describedabove. The system keeps and re-uses the Menu you define in this method until your activity isdestroyed. If you want to change the Options Menu any time after its first created, you must overridethe onPrepareOptionsMenu() method. This passes you the Menu object as it currently exists. This isuseful if youd like to remove, add, disable, or enable menu items depending on the current state ofyour application.On Android 2.3 and lower, the system calls onPrepareOptionsMenu() each time the user opens theOptions Menu.On Android 3.0 and higher, you must call invalidateOptionsMenu() when you want to update the menu,because the menu is always open. The system will then call onPrepareOptionsMenu() so you canupdate the menu items. Note: You should never change items in the Options Menu based on the View currently in focus. When in touch mode (when the user is not using a trackball or d-pad), views cannot take focus, so you should never use focus as the basis for modifying items in the Options Menu. If you want to provide menu items that are context-sensitive to a View, use a Context Menu.If youre developing for Android 3.0 or higher, be sure to also read Using the Action Bar.Creating a Context MenuA context menu is conceptually similar to the menu displayed when the user performs a "right-click" ona PC. You should use a context menu to provide the user access to actions that pertain to a specificitem in the user interface. On Android, a context menu is displayed when the user performs a "longpress" (press and hold) on an item.You can create a context menu for any View, though context menus are most often used for items in aListView. When the user performs a long-press on an item in a ListView and the list is registered to
  15. 15. provide a context menu, the list item signals to the user that a context menu is available by animatingits background color—it transitions from orange to white before opening the context menu. (TheContacts application demonstrates this feature.)Register a ListViewIf your activity uses a ListView and you want all list items to provide a context menu, register all itemsfor a context menu by passing the ListView to registerForContextMenu(). For example, if youre usinga ListActivity, register all list items like this:registerForContextMenu(getListView());In order for a View to provide a context menu, you must "register" the view for a context menu. CallregisterForContextMenu() and pass it the View you want to give a context menu. When this View thenreceives a long-press, it displays a context menu.To define the context menus appearance and behavior, override your activitys context menu callbackmethods, onCreateContextMenu() and onContextItemSelected().For example, heres an onCreateContextMenu() that uses the context_menu.xml menu resource: @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.context_menu, menu); }MenuInflater is used to inflate the context menu from a menu resource. (You can also use add() to addmenu items.) The callback method parameters include the View that the user selected and aContextMenu.ContextMenuInfo object that provides additional information about the item selected.You might use these parameters to determine which context menu should be created, but in thisexample, all context menus for the activity are the same.Then when the user selects an item from the context menu, the system calls onContextItemSelected().Here is an example of how you can handle selected items: @Override public boolean onContextItemSelected(MenuItem item) { AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); switch (item.getItemId()) { case R.id.edit: editNote(info.id); return true; case R.id.delete: deleteNote(info.id); return true;
  16. 16. default: return super.onContextItemSelected(item); } }The structure of this code is similar to the example for Creating an Options Menu, in which getItemId()queries the ID for the selected menu item and a switch statement matches the item to the IDs that aredefined in the menu resource. And like the options menu example, the default statement calls thesuper class in case it can handle menu items not handled here, if necessary.In this example, the selected item is an item from a ListView. To perform an action on the selecteditem, the application needs to know the list ID for the selected item (its position in the ListView). To getthe ID, the application calls getMenuInfo(), which returns a AdapterView.AdapterContextMenuInfoobject that includes the list ID for the selected item in the id field. The local methods editNote() anddeleteNote() methods accept this list ID to perform an action on the data specified by the list ID. Note: Items in a context menu do not support icons or shortcut keys.Creating SubmenusA submenu is a menu that the user can open by selecting an item in another menu. You can add asubmenu to any menu (except a submenu). Submenus are useful when your application has a lot offunctions that can be organized into topics, like items in a PC applications menu bar (File, Edit, View,etc.).When creating your menu resource, you can create a submenu by adding a <menu> element as thechild of an <item>. For example: <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/file" android:icon="@drawable/file" android:title="@string/file" > <!-- "file" submenu --> <menu> <item android:id="@+id/create_new" android:title="@string/create_new" /> <item android:id="@+id/open" android:title="@string/open" /> </menu> </item> </menu>When the user selects an item from a submenu, the parent menus respective on-item-selectedcallback method receives the event. For instance, if the above menu is applied as an Options Menu,then the onOptionsItemSelected() method is called when a submenu item is selected.
  17. 17. You can also use addSubMenu() to dynamically add a SubMenu to an existing Menu. This returns the new SubMenu object, to which you can add submenu items, using add() Other Menu Features Here are some other features that you can apply to most menu items. Menu groups A menu group is a collection of menu items that share certain traits. With a group, you can: Show or hide all items with setGroupVisible() Enable or disable all items with setGroupEnabled() Specify whether all items are checkable with setGroupCheckable() You can create a group by nesting <item> elements inside a <group> element in your menu resource or by specifying a group ID with the the add() method. Heres an example menu resource that includes a group: <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/item1" android:icon="@drawable/item1" android:title="@string/item1" /> <!-- menu group --> <group android:id="@+id/group1"> <item android:id="@+id/groupItem1" android:title="@string/groupItem1" /> <item android:id="@+id/groupItem2" android:title="@string/groupItem2" /> </group> </menu> The items that are in the group appear the same as the first item that is not in a group—all three items in the menu are siblings. However, you can modify the traits of the two items in the group by referencing the group ID and using the methods listed above. Checkable menu items Figure 3. Screenshot of a submenu with checkable items. A menu can be useful as an interface for turning options on and off, using a checkbox for stand-alone options, or radio buttons for groups of mutually exclusive
  18. 18. options. Figure 2 shows a submenu with items that are checkable with radio buttons. Note: Menu items in the Icon Menu (from the Options Menu) cannot display a checkbox or radio button. If you choose to make items in the Icon Menu checkable, you must manually indicate the checked state by swapping the icon and/or text each time the state changes.You can define the checkable behavior for individual menu items using the android:checkable attributein the <item> element, or for an entire group with the android:checkableBehavior attribute in the<group> element. For example, all items in this menu group are checkable with a radio button: <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <group android:checkableBehavior="single"> <item android:id="@+id/red" android:title="@string/red" /> <item android:id="@+id/blue" android:title="@string/blue" /> </group> </menu>The android:checkableBehavior attribute accepts either:single Only one item from the group can be checked (radio buttons)all All items can be checked (checkboxes)none No items are checkableYou can apply a default checked state to an item using the android:checked attribute in the <item>element and change it in code with the setChecked() method.When a checkable item is selected, the system calls your respective item-selected callback method(such as onOptionsItemSelected()). It is here that you must set the state of the checkbox, because acheckbox or radio button does not change its state automatically. You can query the current state ofthe item (as it was before the user selected it) with isChecked() and then set the checked state withsetChecked(). For example: @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.vibrate: case R.id.dont_vibrate: if (item.isChecked()) item.setChecked(false); else item.setChecked(true);
  19. 19. return true; default: return super.onOptionsItemSelected(item); } }If you dont set the checked state this way, then the visible state of the item (the checkbox or radiobutton) will not change when the user selects it. When you do set the state, the activity preserves thechecked state of the item so that when the user opens the menu later, the checked state that you set isvisible. Note: Checkable menu items are intended to be used only on a per-session basis and not saved after the application is destroyed. If you have application settings that you would like to save for the user, you should store the data using Shared Preferences.Shortcut keysTo facilitate quick access to items in the Options Menu when the users device has a hardwarekeyboard, you can add quick-access shortcut keys using letters and/or numbers, with theandroid:alphabeticShortcut and android:numericShortcut attributes in the <item> element. You canalso use the methods setAlphabeticShortcut(char) and setNumericShortcut(char). Shortcut keys arenot case sensitive.For example, if you apply the "s" character as an alphabetic shortcut to a "save" menu item, then whenthe menu is open (or while the user holds the MENU button) and the user presses the "s" key, the"save" menu item is selected.This shortcut key is displayed as a tip in the menu item, below the menu item name (except for itemsin the Icon Menu, which are displayed only if the user holds the MENU button). Note: Shortcut keys for menu items only work on devices with a hardware keyboard. Shortcuts cannot be added to items in a Context Menu.Dynamically adding menu intentsSometimes youll want a menu item to launch an activity using an Intent (whether its an activity in yourapplication or another application). When you know the intent you want to use and have a specificmenu item that should initiate the intent, you can execute the intent with startActivity() during theappropriate on-item-selected callback method (such as the onOptionsItemSelected() callback).However, if you are not certain that the users device contains an application that handles the intent,then adding a menu item that invokes it can result in a non-functioning menu item, because the intentmight not resolve to an activity. To solve this, Android lets you dynamically add menu items to yourmenu when Android finds activities on the device that handle your intent.To add menu items based on available activities that accept an intent:
  20. 20. 1. Define an intent with the category CATEGORY_ALTERNATIVE and/or CATEGORY_SELECTED_ALTERNATIVE, plus any other requirements.2. Call Menu.addIntentOptions(). Android then searches for any applications that can perform the intent and adds them to your menu. If there are no applications installed that satisfy the intent, then no menu items are added. Note: CATEGORY_SELECTED_ALTERNATIVE is used to handle the currently selected element on the screen. So, it should only be used when creating a Menu in onCreateContextMenu(). For example: @Override public boolean onCreateOptionsMenu(Menu menu){ super.onCreateOptionsMenu(menu); // Create an Intent that describes the requirements to fulfill, to be included // in our menu. The offering app must include a category value of Intent.CATEGORY_ALTERNATIVE. Intent intent = new Intent(null, dataUri); intent.addCategory(Intent.CATEGORY_ALTERNATIVE); // Search and populate the menu with acceptable offering applications. menu.addIntentOptions( R.id.intent_group, // Menu group to which new items will be added 0, // Unique item ID (none) 0, // Order for the items (none) this.getComponentName(), // The current activity name null, // Specific items to place first (none) intent, // Intent created above that describes our requirements 0, // Additional flags to control items (none) null); // Array of MenuItems that correlate to specific items (none) return true; } For each activity found that provides an intent filter matching the intent defined, a menu item is added, using the value in the intent filters android:label as the menu item title and the application icon as the menu item icon. The addIntentOptions() method returns the number of menu items added. Note: When you call addIntentOptions(), it overrides any and all menu items by the menu group specified in the first argument. Allowing your activity to be added to other menus You can also offer the services of your activity to other applications, so your application can be included in the menu of others (reverse the roles described above).
  21. 21. To be included in other application menus, you need to define an intent filter as usual, but be sure to include the CATEGORY_ALTERNATIVE and/or CATEGORY_SELECTED_ALTERNATIVE values for the intent filter category. For example: <intent-filter label="Resize Image"> ... <category android:name="android.intent.category.ALTERNATIVE" /> <category android:name="android.intent.category.SELECTED_ALTERNATIVE" /> ... </intent-filter> Read more about writing intent filters in the Intents and Intent Filters document. For a sample application using this technique, see the Note Pad sample code. Using the action bar. The Action Bar is a widget for activities that replaces the traditional title bar at the top of the screen. By default, the Action Bar includes the application logo on the left side, followed by the activity title, and any available items from the Options Menu on the right side. The Action Bar offers several useful features, including the ability to: Display items from the Options Menu directly in the Action Bar, as "action items"—providing instant access to key user actions. Menu items that do not appear as action items are placed in the overflow menu, revealed by a drop- down list in the Action Bar. Provide tabs for navigating between fragments. Provide a drop-down list for navigation. Provide interactive "action views" in place of action items (such as a search box). Figure 1. A screenshot of the Action Bar in the Email application, containing action items to compose new email and refresh the inbox. Adding the Action Bar The Action Bar is included by default in all activities that target Android 3.0 or greater. More specifically, all activities that use the new "holographic" theme include the Action Bar, and any application that targets Android 3.0 automatically receives this theme. An application is considered to "target" Android 3.0 when it has set either the android:minSdkVersion or android:targetSdkVersion attribute in the <uses-sdk> element to "11" or greater. For example:
  22. 22. <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.helloworld" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="11" /> <application ... > ... </application> </manifest>In this example, the application requires a minimum version of API Level 4 (Android 1.6), but it alsotargets API Level 11 (Android 3.0). This way, when the application is installed on a device runningAndroid 3.0 or greater, the system applies the holographic theme to each activity, and thus, eachactivity includes the Action Bar.However, if you want to use Action Bar APIs, such as to add tabs or modify Action Bar styles, youneed to set the android:minSdkVersion to "11", so you can access the ActionBar class.Removing the Action BarIf you want to remove the Action Bar for a particular activity, set the activity theme toTheme.Holo.NoActionBar. For example: <activity android:theme="@android:style/Theme.Holo.NoActionBar"> Tip: If you have a custom activity theme in which youd like to remove the Action Bar, set the android:windowActionBar style property false. See Styling the Action Bar for more about Action Bar styles.You can also hide the Action Bar at runtime by calling hide(), then show it again by calling show(). Forexample: ActionBar actionBar = getActionBar(); actionBar.hide();When the Action Bar hides, the system adjusts your activity content to fill all the available screenspace. Note: If you remove the Action Bar using a theme, then the window will not allow the Action Bar at all, so you cannot add it at runtime—calling getActionBar() will return null.Adding Action Items
  23. 23. An action item is simply a menu item from the Options Menu which you declare should appear directlyin the Action Bar. An action item can include an icon and/or text. If a menu item does not appear as anaction item, then the system places it in the overflow menu, which the user can open with the menuicon on the right side of the Action Bar.Figure 2. A screenshot from an Action Bar with two action items and the overflow menu.When the activity first starts, the system populates the Action Bar and overflow menu by callingonCreateOptionsMenu() for your activity. As discussed in the guide to Creating Menus, its in thiscallback method that you define the Options Menu for the activity.You can specify a menu item to appear as an action item—if there is room for it—from your menuresource by declaring android:showAsAction="ifRoom" for the <item> element. This way, the menuitem appears in the Action Bar for quick access only if there is room available for it. If theres notenough room, the item is placed the overflow menu (revealed by the menu icon on the right side of theAction Bar).You can also declare a menu item to appear as an action item from your application code, by callingsetShowAsAction() on the MenuItem and passing SHOW_AS_ACTION_IF_ROOM.If your menu item supplies both a title and an icon, then the action item shows only the icon by defult. Ifyou want to include the text with the action item, add the "with text" flag: in XML, add withText to theandroid:showAsAction attribute or, in your application code, use theSHOW_AS_ACTION_WITH_TEXT flag when calling setShowAsAction(). Figure 2 shows an ActionBar that has two action items with text and the icon for the overflow menu.Heres an example of how you can declare a menu item as an action item in a menu resource file: <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/menu_save" android:icon="@drawable/ic_menu_save" android:title="@string/menu_save" android:showAsAction="ifRoom|withText" /> </menu>In this case, both the ifRoom and withText flags are set, so that when this item appears as an actionitem, it includes the title text along with the icon.A menu item placed in the Action Bar triggers the same callback methods as other items in the OptionsMenu. When the user selects an action item, your activity receives a call to onOptionsItemSelected(),passing the item ID.
  24. 24. Note: If you added the menu item from a fragment, then the respective onOptionsItemSelected() method is called for that fragment. However the activity gets a chance to handle it first, so the system calls onOptionsItemSelected() on the activity before calling the fragment.You can also declare an item to always appear as an action item, but you should avoid doing so,because it can create a cluttered UI if there are too many action items and they might collide with otherelements in the Action Bar.For more information about menus, see the Creating Menus developer guide.Using the app icon as an action itemBy default, your application icon appears in the Action Bar on the left side. It also responds to userinteraction (when the user taps it, it visually responds the same way action items do) and its yourresponsibility to do something when the user taps it. Figure 3. Emails Action Bar, with the application icon on the left.The normal behavior should be for your application to return to the "home" activity or the initial state(such as when the activity hasnt changed, but fragments have changed) when the user taps the icon.If the user is already at home or the initial state, then you dont need to do anything.When the user taps the icon, the system calls your activitys onOptionsItemSelected() method with theandroid.R.id.home ID. So, you need to add a condition to your onOptionsItemSelected() method tolisten for android.R.id.home and perform the appropriate action, such as start the home activity or poprecent fragment transactions off the stack.If you respond to the application icon by returning to the home activity, you should include theFLAG_ACTIVITY_CLEAR_TOP flag in the Intent. With this flag, if the activity youre starting alreadyexists in the current task, then all activities on top of it are destroyed and it is brought to the front. Youshould favor this approach, because going "home" is an action thats equivalent to "going back" andyou should usually not create a new instance of the home activity. Otherwise, you might end up with along stack of activities in the current task.For example, heres an implementation of onOptionsItemSelected() that returns to the applications"home" activity: @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: // app icon in Action Bar clicked; go home Intent intent = new Intent(this, HomeActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent);
  25. 25. return true; default: return super.onOptionsItemSelected(item); } }Using the app icon to navigate "up"Figure 4. The standard icon for the Email application (top) and the "up" icon (bottom). You can also use the application icon to provide "up" navigation for the user. This is especially useful when your application is composed of activities that generally appear in a certain order and you want to facilitate the ability for the user to navigate up the activity hierarchy (regardless of how they entered the current activity). The way you respond to this event is the same as when navigating home (as discussed above, except you start a different activity, based on the currentactivity). All you need to do to indicate to the user that the behavior is different is set the Action Bar to"show home as up." You can do so by calling setDisplayHomeAsUpEnabled(true) on your activitysActionBar. When you do, the system draws your application icon with an arrow indicating the upbehavior, as shown in figure 4.For example, heres how you can show the application icon as an "up" action: @Override protected void onStart() { super.onStart(); ActionBar actionBar = this.getActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); }Then, your activity should respond to the user tapping the icon, from the onOptionsItemSelected(), bylistening for the android.R.id.home ID (as shown above). In this case, when navigating up, its evenmore important that you use the FLAG_ACTIVITY_CLEAR_TOP flag in the Intent, so that you dontcreate a new instance of the parent activity if one already exists.Adding an Action ViewFigure 5. An action view with a SearchView widget.
  26. 26. An action view is a widget that appears in the Action Bar as a substitute for an action item. For example, if you have an item in the Options Menu for "Search", you can add an action view for the item that provides a SearchView widget in the Action Bar whenever the item is enabled as an action item. When adding an action view for a menu item, its important that you still allow the item to behave as a normal menu item when it does not appear in the Action Bar. For example, a menu item to perform a search should, by default, bring up the Android search dialog, but if the item is placed in the Action Bar, the action view appears with a SearchView widget. Figure 4 shows an example of the SearchView widget in an action view. The best way to declare an action view for an item is in your menu resource, using the android:actionLayout or android:actionViewClass attribute: The value for android:actionLayout must be a resource pointer to a layout file. For example: <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/menu_search" android:title="Search" android:icon="@drawable/ic_menu_search" android:showAsAction="ifRoom" android:actionLayout="@layout/searchview" /> </menu> The value for android:actionViewClass must be a fully-qualified class name for the View you want to use. For example: <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/menu_search" android:title="Search" android:icon="@drawable/ic_menu_search" android:showAsAction="ifRoom" android:actionViewClass="android.widget.SearchView" /> </menu> You must include android:showAsAction="ifRoom" in order for the item to appear as an action view when room is available. If necessary, however, you can force the item to always appear as an action view by setting android:showAsAction to "always". Now, when the menu item is displayed as an action item, its action view appears instead of the icon and/or title text. However, if theres not enough room in the Action Bar, the item appears in the overflow menu as a normal menu item and you must respond to it from the onOptionsItemSelected() callback method.
  27. 27. When the activity first starts, the system populates the Action Bar and overflow menu by calling onCreateOptionsMenu(). After youve inflated your menu in this method, you can acquire elements in an action view (perhaps in order to attach listeners) by calling findItem() with the ID of the menu item, then getActionView() on the returned MenuItem. For example, the search widget from the above samples is acquired like this: @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.options, menu); SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView(); // Set appropriate listeners for searchView ... return super.onCreateOptionsMenu(menu); } For more information about using the search widget, see Creating a Search Interface. Adding Tabs Figure 6. Screenshot of tabs in the Action Bar, from the Honeycomb Gallery sample application. The Action Bar can display tabs that allow the user navigate between different fragments in the activity. Each tab can include a title and/or an icon. To begin, your layout must include a View in which each Fragment associated with a tab is displayed. Be sure the view has an ID that you can use to reference it from your code. To add tabs to the Action Bar:1. Create an implementation of ActionBar.TabListener to handle the interaction events on the Action Bar tabs. You must implement all methods: onTabSelected(), onTabUnselected(), and onTabReselected(). Each callback method passes the ActionBar.Tab that received the event and a FragmentTransaction for you to perform the fragment transactions (add or remove fragments). For example: private class MyTabListener implements ActionBar.TabListener { private TabContentFragment mFragment; // Called to create an instance of the listener when adding a new tab public MyTabListener(TabContentFragment fragment) { mFragment = fragment;
  28. 28. } public void onTabSelected(Tab tab, FragmentTransaction ft) { ft.add(R.id.fragment_content, mFragment, null); } public void onTabUnselected(Tab tab, FragmentTransaction ft) { ft.remove(mFragment); } public void onTabReselected(Tab tab, FragmentTransaction ft) { // do nothing } } This implementation of ActionBar.TabListener adds a constructor that saves the Fragment associated with a tab so that each callback can add or remove that fragment.2. Get the ActionBar for your activity by calling getActionBar() from your Activity, during onCreate() (but be sure you do so after youve called setContentView()).3. Call setNavigationMode(NAVIGATION_MODE_TABS) to enable tab mode for the ActionBar.4. Create each tab for the Action Bar:1. Create a new ActionBar.Tab by calling newTab() on the ActionBar.2. Add title text and/or an icon for the tab by calling setText() and/or setIcon(). Tip: These methods return the same ActionBar.Tab instance, so you can chain the calls together.3. Declare the ActionBar.TabListener to use for the tab by passing an instance of your implementation to setTabListener().5. Add each ActionBar.Tab to the Action Bar by calling addTab() on the ActionBar and passing the ActionBar.Tab. For example, the following code combines steps 2 - 5 to create two tabs and add them to the Action Bar: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // setup Action Bar for tabs final ActionBar actionBar = getActionBar(); actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); // remove the activity title to make space for tabs actionBar.setDisplayShowTitleEnabled(false); // instantiate fragment for the tab Fragment artistsFragment = new ArtistsFragment();
  29. 29. // add a new tab and set its title text and tab listener actionBar.addTab(actionBar.newTab().setText(R.string.tab_artists) .setTabListener(new TabListener(artistsFragment))); Fragment albumsFragment = new AlbumsFragment(); actionBar.addTab(actionBar.newTab().setText(R.string.tab_albums) .setTabListener(new TabListener(albumsFragment))); } All the behaviors that occur when a tab is selected must be defined by your ActionBar.TabListener callback methods. When a tab is selected, it receives a call to onTabSelected() and thats where you should add the appropriate fragment to the designated view in your layout, using add() with the provided FragmentTransaction. Likewise, when a tab is deselected (because another tab becomes selected), you should remove that fragment from the layout, using remove(). Caution: You must not call commit() for these transactions—the system calls it for you and it may throw an exception if you call it yourself. You also cannot add these fragment transactions to the back stack. If your activity is stopped, you should retain the currently selected tab with the saved state so that when the user returns to your application, you can open the tab. When its time to save the state, you can query the currently selected tab with getSelectedNavigationIndex(). This returns the index position of the selected tab. Caution: Its important that you save the state of each fragment as necessary, so when the user switches fragments with the tabs, then returns to a previous fragment, it appears the way they left. For information about saving the state of your fragment, see the Fragments developer guide. Adding Drop-down Navigation As another mode of navigation within your activity, you can provide a drop-down list in the Action Bar. For example, the drop-down list can provide alternative modes for sorting the content in the activity or switching the users account. Heres a quick list of steps to enable drop-down navigation:1. Create a SpinnerAdapter that provides the list of selectable items for the drop-down and the layout to use when drawing each item in the list.2. Implement ActionBar.OnNavigationListener to define the behavior when the user selects an item from the list.3. Enable navigation mode for the Action Bar with setNavigationMode(). For example: ActionBar actionBar = getActionBar(); actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); Note: You should perform this during your activitys onCreate() method.
  30. 30. 4. Then, set the callback for the drop-down list with setListNavigationCallbacks(). For example: actionBar.setListNavigationCallbacks(mSpinnerAdapter, mNavigationCallback); This method takes your SpinnerAdapter and ActionBar.OnNavigationListener. More about these next. Thats the basic setup. However, implementing the SpinnerAdapter and ActionBar.OnNavigationListener is where most of the work is done. There are many ways you can implement these to define the functionality for your drop-down navigation and implementing various types of SpinnerAdapter is beyond the scope of this document (you should refer to the SpinnerAdapter class reference for more information). However, below is a simple example for a SpinnerAdapter and ActionBar.OnNavigationListener to get you started (click the title to reveal the sample). Example SpinnerAdapter and OnNavigationListener SpinnerAdapter is an adapter that provides data for a spinner widget, such as the drop-down list in the Action Bar. SpinnerAdapter is an interface that you can implement, but Android includes some useful implementations that you can extend, such as ArrayAdapter and SimpleCursorAdapter. For example, heres an easy way to create a SpinnerAdapter by using ArrayAdapter implementation, which uses a string array as the data source: SpinnerAdapter mSpinnerAdapter = ArrayAdapter.createFromResource(this, R.array.action_list, android.R.layout.simple_spinner_dropdown_item); The createFromResource() method takes three parameters: the application Context, the resource ID for the string array, and the layout to use for each list item. A string array defined in a resource looks like this: <?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="action_list"> <item>Mercury</item> <item>Venus</item> <item>Earth</item> </string-array> </pre> The ArrayAdapter returned by createFromResource() is complete and ready for you to pass it to setListNavigationCallbacks() (in step 4 from above). Before you do, though, you need to create the OnNavigationListener. Your implementation of ActionBar.OnNavigationListener is where you handle fragment changes or other modifications to your activity when the user selects an item from the drop-down list. Theres only one callback method to implement in the listener: onNavigationItemSelected().
  31. 31. The onNavigationItemSelected() method receives the position of the item in the list and a unique itemID provided by the SpinnerAdapter.Heres an example that instantiates an anonymous implementation of OnNavigationListener, whichinserts a Fragment into the layout container identified by R.id.fragment_container: mOnNavigationListener = new OnNavigationListener() { // Get the same strings provided for the drop-downs ArrayAdapter String[] strings = getResources().getStringArray(R.array.action_list); @Override public boolean onNavigationItemSelected(int position, long itemId) { // Create new fragment from our own Fragment class ListContentFragment newFragment = new ListContentFragment(); FragmentTransaction ft = openFragmentTransaction(); // Replace whatever is in the fragment container with this fragment // and give the fragment a tag name equal to the string at the position selected ft.replace(R.id.fragment_container, newFragment, strings[position]); // Apply changes ft.commit(); return true; } };This instance of OnNavigationListener is complete and you can now call setListNavigationCallbacks()(in step 4), passing the ArrayAdapter and this OnNavigationListener.In this example, when the user selects an item from the drop-down list, a fragment is added to thelayout (replacing the current fragment in the R.id.fragment_container view). The fragment added isgiven a tag that uniquely identifies it, which is the same string used to identify the fragment in the drop-down list.Heres a look at the ListContentFragment class that defines each fragment in this example: public class ListContentFragment extends Fragment { private String mText; @Override public void onAttach(Activity activity) { // This is the first callback received; here we can set the text for // the fragment as defined by the tag specified during the fragment transaction super.onAttach(activity); mText = getTag(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
  32. 32. // This is called to define the layout for the fragment; // we just create a TextView and set its text to be the fragment tag TextView text = new TextView(getActivity()); text.setText(mText); return text; } }Styling the Action BarThe Action Bar is the heading for your application and a primary interaction point for users, so youmight want to modify some of its design in order to make it feel more integrated with your applicationdesign. There are several ways you can do this if you wish.For simple modifications to the ActionBar, you can use the following methods:setBackgroundDrawable() Sets a drawable to use as the Action Bars background. The drawable should be a Nine-patch image, a shape, or a solid color, so the system can resize the drawable based on the size of the Action Bar (you should not use a fixed-size bitmap image).setDisplayUseLogoEnabled() Enables the use of an alternative image (a "logo") in the Action Bar, instead of the default application icon. A logo is often a wider, more detailed image that represents the application. When this is enabled, the system uses the logo image defined for the application (or the individual activity) in the manifest file, with the android:logo attribute. The logo will be resized as necessary to fit the height of the Action Bar. (Best practice is to design the logo at the same size as your application icon.)For more complex customizations, you can use Androids style and theme framework to restyle yourAction Bar in several ways.The Action Bar has two standard themes, "dark" and "light". The dark theme is applied with the defaultholographic theme, as specified by the Theme.Holo theme. If you want a white background with darktext, instead, you can apply the Theme.Holo.Light theme to the activity in the manifest file. Forexample: <activity android:name=".ExampleActivity" android:theme="@android:style/Theme.Holo.Light" />For more control, you can override either the Theme.Holo or Theme.Holo.Light theme and applycustom styles to certain aspects of the Action Bar. Some of the Action Bar properties you cancustomize include the following:android:actionBarTabStyle
  33. 33. Style for tabs in the Action Bar.android:actionBarTabBarStyle Style for the bar that appears below tabs in the Action Bar.android:actionBarTabTextStyle Style for the text in the tabs.android:actionDropDownStyle Style for the drop-down list used for the overflow menu and drop-down navigation.android:actionButtonStyle Style for the background image used for buttons in the Action Bar.For example, heres a resource file that defines a custom theme for the Action Bar, based on thestandard Theme.Holo theme: <?xml version="1.0" encoding="utf-8"?> <resources> <!-- the theme applied to the application or activity --> <style name="CustomActionBar" parent="android:style/Theme.Holo.Light"> <item name="android:actionBarTabTextStyle">@style/customActionBarTabTextStyle</item> <item name="android:actionBarTabStyle">@style/customActionBarTabStyle</item> <item name="android:actionBarTabBarStyle">@style/customActionBarTabBarStyle</item> </style> <!-- style for the tab text --> <style name="customActionBarTabTextStyle"> <item name="android:textColor">#2966c2</item> <item name="android:textSize">20sp</item> <item name="android:typeface">sans</item> </style> <!-- style for the tabs --> <style name="customActionBarTabStyle"> <item name="android:background">@drawable/actionbar_tab_bg</item> <item name="android:paddingLeft">20dp</item> <item name="android:paddingRight">20dp</item> </style> <!-- style for the tab bar --> <style name="customActionBarTabBarStyle"> <item name="android:background">@drawable/actionbar_tab_bar</item> </style> </resources> Note: In order for the tab background image to change, depending on the current tab state (selected, pressed, unselected), the drawable resource used must be a state list drawable. Also
  34. 34. be certain that your theme declares a parent theme, from which it inherits all styles not explicitly declared in your theme.You can apply your custom theme to the entire application or to individual activities in your manifestfile, like this: <application android:theme="@style/CustomActionBar" ... />Additionally, if you want to create a custom theme for your activity that removes the Action Barcompletely, use the following style attributes:android:windowActionBar Set this style property false to remove the Action Bar.android:windowNoTitle Set this style property true to also remove the traditional title bar.For more information about using themes in your application, read Applying Styles and Themes.Creating Dialogs.A dialog is usually a small window that appears in front of the current Activity. The underlying Activityloses focus and the dialog accepts all user interaction. Dialogs are normally used for notifications thatshould interupt the user and to perform short tasks that directly relate to the application in progress(such as a progress bar or a login prompt).The Dialog class is the base class for creating dialogs. However, you typically should not instantiate aDialog directly. Instead, you should use one of the following subclasses:AlertDialog A dialog that can manage zero, one, two, or three buttons, and/or a list of selectable items that can include checkboxes or radio buttons. The AlertDialog is capable of constructing most dialog user interfaces and is the suggested dialog type. See Creating an AlertDialog below.ProgressDialog A dialog that displays a progress wheel or progress bar. Because its an extension of the AlertDialog, it also supports buttons. See Creating a ProgressDialog below.DatePickerDialog A dialog that allows the user to select a date. See the Hello DatePicker tutorial.TimePickerDialog A dialog that allows the user to select a time. See the Hello TimePicker tutorial.
  35. 35. If you would like to customize your own dialog, you can extend the base Dialog object or any of thesubclasses listed above and define a new layout. See the section on Creating a Custom Dialog below.Showing a DialogA dialog is always created and displayed as a part of an Activity. You should normally create dialogsfrom within your Activitys onCreateDialog(int) callback method. When you use this callback, theAndroid system automatically manages the state of each dialog and hooks them to the Activity,effectively making it the "owner" of each dialog. As such, each dialog inherits certain properties fromthe Activity. For example, when a dialog is open, the Menu key reveals the options menu defined forthe Activity and the volume keys modify the audio stream used by the Activity. Note: If you decide to create a dialog outside of the onCreateDialog() method, it will not be attached to an Activity. You can, however, attach it to an Activity with setOwnerActivity(Activity).When you want to show a dialog, call showDialog(int) and pass it an integer that uniquely identifies thedialog that you want to display.When a dialog is requested for the first time, Android calls onCreateDialog(int) from your Activity,which is where you should instantiate the Dialog. This callback method is passed the same ID that youpassed to showDialog(int). After you create the Dialog, return the object at the end of the method.Before the dialog is displayed, Android also calls the optional callback method onPrepareDialog(int,Dialog). Define this method if you want to change any properties of the dialog each time it is opened.This method is called every time a dialog is opened, whereas onCreateDialog(int) is only called thevery first time a dialog is opened. If you dont define onPrepareDialog(), then the dialog will remain thesame as it was the previous time it was opened. This method is also passed the dialogs ID, along withthe Dialog object you created in onCreateDialog().The best way to define the onCreateDialog(int) and onPrepareDialog(int, Dialog) callback methods iswith a switch statement that checks the id parameter thats passed into the method. Each case shouldcheck for a unique dialog ID and then create and define the respective Dialog. For example, imagine agame that uses two different dialogs: one to indicate that the game has paused and another to indicatethat the game is over. First, define an integer ID for each dialog: static final int DIALOG_PAUSED_ID = 0; static final int DIALOG_GAMEOVER_ID = 1;Then, define the onCreateDialog(int) callback with a switch case for each ID: protected Dialog onCreateDialog(int id) { Dialog dialog; switch(id) { case DIALOG_PAUSED_ID: // do the work to define the pause Dialog
  36. 36. break; case DIALOG_GAMEOVER_ID: // do the work to define the game over Dialog break; default: dialog = null; } return dialog; } Note: In this example, theres no code inside the case statements because the procedure for defining your Dialog is outside the scope of this section. See the section below about Creating an AlertDialog, offers code suitable for this example.When its time to show one of the dialogs, call showDialog(int) with the ID of a dialog: showDialog(DIALOG_PAUSED_ID);Dismissing a DialogWhen youre ready to close your dialog, you can dismiss it by calling dismiss() on the Dialog object. Ifnecessary, you can also call dismissDialog(int) from the Activity, which effectively calls dismiss() onthe Dialog for you.If you are using onCreateDialog(int) to manage the state of your dialogs (as discussed in the previoussection), then every time your dialog is dismissed, the state of the Dialog object is retained by theActivity. If you decide that you will no longer need this object or its important that the state is cleared,then you should call removeDialog(int). This will remove any internal references to the object and if thedialog is showing, it will dismiss it.Using dismiss listenersIf youd like your application to perform some procedures the moment that a dialog is dismissed, thenyou should attach an on-dismiss listener to your Dialog.First define the DialogInterface.OnDismissListener interface. This interface has just one method,onDismiss(DialogInterface), which will be called when the dialog is dismissed. Then simply pass yourOnDismissListener implementation to setOnDismissListener().However, note that dialogs can also be "cancelled." This is a special case that indicates the dialog wasexplicitly cancelled by the user. This will occur if the user presses the "back" button to close the dialog,or if the dialog explicitly calls cancel() (perhaps from a "Cancel" button in the dialog). When a dialog iscancelled, the OnDismissListener will still be notified, but if youd like to be informed that the dialogwas explicitly cancelled (and not dismissed normally), then you should register anDialogInterface.OnCancelListener with setOnCancelListener().
  37. 37. Creating an AlertDialog An AlertDialog is an extension of the Dialog class. It is capable of constructing most dialog user interfaces and is the suggested dialog type. You should use it for dialogs that use any of the following features: A title A text message One, two, or three buttons A list of selectable items (with optional checkboxes or radio buttons) To create an AlertDialog, use the AlertDialog.Builder subclass. Get a Builder with AlertDialog.Builder(Context) and then use the classs public methods to define all of the AlertDialog properties. After youre done with the Builder, retrieve the AlertDialog object with create(). The following topics show how to define various properties of the AlertDialog using the AlertDialog.Builder class. If you use any of the following sample code inside your onCreateDialog() callback method, you can return the resulting Dialog object to display the dialog. Adding buttons To create an AlertDialog with side-by-side buttons like the one shown in the screenshot to the right, use the set...Button() methods: AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage("Are you sure you want to exit?") .setCancelable(false) .setPositiveButton("Yes", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { MyActivity.this.finish(); } }) .setNegativeButton("No", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } }); AlertDialog alert = builder.create(); First, add a message for the dialog with setMessage(CharSequence). Then, begin method-chaining and set the dialog to be not cancelable (so the user cannot close the dialog with the back button) with setCancelable(boolean). For each button, use one of the set...Button() methods, such as setPositiveButton(), that accepts the name for the button and a DialogInterface.OnClickListener that defines the action to take when the user selects the button.
  38. 38. Note: You can only add one of each button type to the AlertDialog. That is, you cannot have more than one "positive" button. This limits the number of possible buttons to three: positive, neutral, and negative. These names are technically irrelevant to the actual functionality of your buttons, but should help you keep track of which one does what. Adding a list To create an AlertDialog with a list of selectable items like the one shown to the right, use the setItems() method: final CharSequence[] items = {"Red", "Green", "Blue"}; AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Pick a color"); builder.setItems(items, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int item) { Toast.makeText(getApplicationContext(), items[item], Toast.LENGTH_SHORT).show(); } }); AlertDialog alert = builder.create();First, add a title to the dialog with setTitle(CharSequence). Then, add a list of selectable items withsetItems(), which accepts the array of items to display and a DialogInterface.OnClickListener thatdefines the action to take when the user selects an item. Adding checkboxes and radio buttons To create a list of multiple-choice items (checkboxes) or single-choice items (radio buttons) inside the dialog, use the setMultiChoiceItems() and setSingleChoiceItems() methods, respectively. If you create one of these selectable lists in the onCreateDialog() callback method, Android manages the state of the list for you. As long as the Activity is active, the dialog remembers the items that were previously selected, butwhen the user exits the Activity, the selection is lost. Note: To save the selection when the user leaves or pauses the Activity, you must properly save and restore the setting throughout the activity lifecycle. To permanently save the selections, even when the Activity process is completely shutdown, you need to save the settings with one of the Data Storage techniques.To create an AlertDialog with a list of single-choice items like the one shown to the right, use the samecode from the previous example, but replace the setItems() method with setSingleChoiceItems():
  39. 39. final CharSequence[] items = {"Red", "Green", "Blue"}; AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Pick a color"); builder.setSingleChoiceItems(items, -1, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int item) { Toast.makeText(getApplicationContext(), items[item], Toast.LENGTH_SHORT).show(); } }); AlertDialog alert = builder.create();The second parameter in the setSingleChoiceItems() method is an integer value for the checkedItem,which indicates the zero-based list position of the default selected item. Use "-1" to indicate that noitem should be selected by default. Creating a ProgressDialog A ProgressDialog is an extension of the AlertDialog class that can display a progress animation in the form of a spinning wheel, for a task withprogress thats undefined, or a progress bar, for a task that has a defined progression. The dialog canalso provide buttons, such as one to cancel a download.Opening a progress dialog can be as simple as calling ProgressDialog.show(). For example, theprogress dialog shown to the right can be easily achieved without managing the dialog through theonCreateDialog(int) callback, as shown here: ProgressDialog dialog = ProgressDialog.show(MyActivity.this, "", "Loading. Please wait...", true);The first parameter is the application Context, the second is a title for the dialog (left empty), the thirdis the message, and the last parameter is whether the progress is indeterminate (this is only relevantwhen creating a progress bar, which is discussed in the next section).The default style of a progress dialog is the spinning wheel. If you want to create a progress bar thatshows the loading progress with granularity, some more code is required, as discussed in the nextsection. Showing a progress bar To show the progression with an animated progress bar: 1. Initialize the ProgressDialog with the class constructor,ProgressDialog(Context).
  40. 40. 2. Set the progress style to "STYLE_HORIZONTAL" with setProgressStyle(int) and set any other properties, such as the message.3. When youre ready to show the dialog, call show() or return the ProgressDialog from the onCreateDialog(int) callback.4. You can increment the amount of progress displayed in the bar by calling either setProgress(int) with a value for the total percentage completed so far or incrementProgressBy(int) with an incremental value to add to the total percentage completed so far. For example, your setup might look like this: ProgressDialog progressDialog; progressDialog = new ProgressDialog(mContext); progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); progressDialog.setMessage("Loading..."); progressDialog.setCancelable(false); The setup is simple. Most of the code needed to create a progress dialog is actually involved in the process that updates it. You might find that its necessary to create a second thread in your application for this work and then report the progress back to the Activitys UI thread with a Handler object. If youre not familiar with using additional threads with a Handler, see the example Activity below that uses a second thread to increment a progress dialog managed by the Activity. Example ProgressDialog with a second thread This example uses a second thread to track the progress of a process (which actually just counts up to 100). The thread sends a Message back to the main Activity through a Handler each time progress is made. The main Activity then updates the ProgressDialog. package com.example.progressdialog; import android.app.Activity; import android.app.Dialog; import android.app.ProgressDialog; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class NotificationTest extends Activity { static final int PROGRESS_DIALOG = 0; Button button; ProgressThread progressThread; ProgressDialog progressDialog; /** Called when the activity is first created. */
  41. 41. public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // Setup the button that starts the progress dialog button = (Button) findViewById(R.id.progressDialog); button.setOnClickListener(new OnClickListener(){ public void onClick(View v) { showDialog(PROGRESS_DIALOG); } });}protected Dialog onCreateDialog(int id) { switch(id) { case PROGRESS_DIALOG: progressDialog = new ProgressDialog(NotificationTest.this); progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); progressDialog.setMessage("Loading..."); return progressDialog; default: return null; }}@Overrideprotected void onPrepareDialog(int id, Dialog dialog) { switch(id) { case PROGRESS_DIALOG: progressDialog.setProgress(0); progressThread = new ProgressThread(handler); progressThread.start();}// Define the Handler that receives messages from the thread and update the progressfinal Handler handler = new Handler() { public void handleMessage(Message msg) { int total = msg.arg1; progressDialog.setProgress(total); if (total >= 100){ dismissDialog(PROGRESS_DIALOG); progressThread.setState(ProgressThread.STATE_DONE); } }};/** Nested class that performs progress calculations (counting) */private class ProgressThread extends Thread { Handler mHandler; final static int STATE_DONE = 0; final static int STATE_RUNNING = 1;