From 258a51e3e687d4d469de501f17dd937cdc29019a Mon Sep 17 00:00:00 2001
From: Scott Main
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:
+The action bar is a window feature that identifies the application and user location, and +provides user actions and navigation modes. You should use the action bar in most activities that +need to prominently present user actions or global navigation, because the action bar offers users a +consistent interface across applications and the system gracefully adapts the action bar's +appearance for different screen configurations. You can control the behaviors and visibility of the +action bar with the {@link android.app.ActionBar} APIs, which were added in Android 3.0 (API level +11).
+ +The primary goals of the action bar are to:
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.
This is accomplished with the app icon or logo on the left side and the activity title. +You might choose to remove the activity title, however, if the current view is identified by a +navigation label, such as the currently selected tab.
The action bar provides built-in tab navigation for switching between fragments. It also offers a drop-down +list you can use as an alternative navigation mode or to refine the current view (such as to sort +a list by different criteria).
+You can provide instant access to key user actions by placing items from the options menu directly in the action bar, +as "action items." Action items can also provide an "action view," which provides an embedded +widget for even more immediate action behaviors. Menu items that are not promoted +to an action item are available in the overflow menu, revealed by either the device MENU button +(when available) or by an "overflow menu" button in the action bar (when the device does not +include a MENU button).
+
+Figure 1. Action bar from the Honeycomb Gallery app (on a +landscape handset), showing the logo on the left, navigation tabs, and an action item on the +right (plus the overflow menu button).
-Figure 1. A screenshot of the Action Bar in the Email -application, containing action items to compose new email and refresh the inbox.
+ +If you want to provide an action bar in your application and remain compatible with +versions of Android older than 3.0, you need to create the action bar in your +activity's layout (because the {@link android.app.ActionBar} class is not available on older +versions).
+To help you, the Action Bar Compatibility sample +app provides an API layer and action bar layout that allows your app to use some of the {@link +android.app.ActionBar} APIs and also support older versions of Android by replacing the traditional +title bar with a custom action bar layout.
+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 {@code android:minSdkVersion} or {@code -android:targetSdkVersion} attribute in the {@code <uses-sdk>} element to -{@code "11"} or greater. For example:
+Beginning with Android 3.0 (API level 11), the action bar is included in all +activities that use the {@link android.R.style#Theme_Holo Theme.Holo} theme (or one of its +descendants), which is the default theme when either the {@code targetSdkVersion} or +{@code minSdkVersion} +attribute is set to {@code "11"} or greater. For example:
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.helloworld"
- android:versionCode="1"
- android:versionName="1.0">
+<manifest ... >
<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 also targets API Level 11 (Android 3.0). This way, when -the application is installed on a device running Android 3.0 or greater, the system applies the -holographic theme to each activity, and thus, each activity includes the Action Bar.
+In this example, the application requires a minimum version of API Level 4 (Android 1.6), but it +also targets API level 11 (Android 3.0). This way, when the application runs on Android 3.0 or +greater, the system applies the holographic theme to each activity, and thus, each activity includes +the action bar.
-However, if you want to use Action Bar APIs, such as to add tabs or modify Action Bar styles, -you need to set the {@code android:minSdkVersion} to {@code "11"}, so you can access the -{@link android.app.ActionBar} class.
+If you want to use {@link android.app.ActionBar} APIs, such as to add navigation modes and modify +action bar styles, you should set the {@code minSdkVersion} to {@code +"11"} or greater. If you want your app +to support older versions of Android, there are ways to use a limited set of {@link +android.app.ActionBar} APIs on devices that support API level 11 or higher, while still running +on older versions. See the sidebox for information about remaining backward-compatible.
-If you want to remove the Action Bar for a particular activity, set the activity theme to +
If you don't want the action bar for a particular activity, set the activity theme to {@link android.R.style#Theme_Holo_NoActionBar Theme.Holo.NoActionBar}. For example:
<activity android:theme="@android:style/Theme.Holo.NoActionBar">-
Tip: If you have a custom activity theme in which you'd like to -remove the Action Bar, set the {@link android.R.styleable#Theme_windowActionBar -android:windowActionBar} style property {@code false}. See Styling the Action -Bar for more about Action Bar styles.
- -You can also hide the Action Bar at runtime by calling {@link android.app.ActionBar#hide}, -then show it again by calling {@link android.app.ActionBar#show}. For example:
+You can also hide the action bar at runtime by calling {@link android.app.ActionBar#hide}. For +example:
-ActionBar actionBar = getActionBar();
+ActionBar actionBar = {@link android.app.Activity#getActionBar()};
actionBar.hide();
-When the Action Bar hides, the system adjusts your activity content to fill all the -available screen space.
+When the action bar hides, the system adjusts your activity layout to fill all the +screen space now available. You can bring the action bar back with {@link +android.app.ActionBar#show()}.
+ +Beware that hiding and removing the action bar causes your activity to re-layout in order to +account for the space consumed by the action bar. If your activity regularly hides and shows the +action bar (such as in the Android Gallery app), you might want to use overlay mode. Overlay mode +draws the action bar on top of your activity layout rather than in its own area of the screen. This +way, your layout remains fixed when the action bar hides and re-appears. To enable overlay mode, +create a theme for your activity and set {@link android.R.attr#windowActionBarOverlay +android:windowActionBarOverlay} to {@code true}. For more information, see the section about Styling the Action Bar.
+ +Tip: If you have a custom activity theme in which you'd like to +remove the action bar, set the {@link android.R.styleable#Theme_windowActionBar +android:windowActionBar} style property to {@code false}. However, 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 +later—calling {@link android.app.Activity#getActionBar()} will return null.
-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 -{@link android.app.Activity#getActionBar getActionBar()} will return null.
An action item is simply a menu item from the Options Menu which you declare should -appear directly in the Action Bar. An action item can include an icon and/or text. If a menu -item does not appear as an action item, then the system places it in the overflow menu, which -the user can open with the menu icon on the right side of the Action Bar.
+Sometimes you might want to give users immediate access to an item from the options menu. To do this, you can +declare that the menu item should appear in the action bar as an "action item." An action item can +include an icon and/or a text title. If a menu item does not appear as an action item, then the +system places it in the overflow menu. The overflow menu is revealed either by the device MENU +button (if provided by the device) or an additional button in the action bar (if the device does not +provide the MENU button).
- Figure 2. A screenshot from an Action Bar with two -action items and the overflow menu.
+Figure 2. Two action items with icon and text titles, and +the overflow menu button.
When the activity first starts, the system populates the Action Bar and overflow menu by calling +
When the activity first starts, the system populates the action bar and overflow menu by calling {@link android.app.Activity#onCreateOptionsMenu onCreateOptionsMenu()} for your activity. As -discussed in the Menus developer guid, it's in -this callback method that you define the Options Menu for the activity.
+discussed in the Menus developer guide, it's in +this callback method that you should inflate an XML menu resource that defines the +menu items. For example: -You can specify a menu item to appear as an action item—if there is room -for it—from your menu -resource by declaring {@code +
+@Override
+public boolean onCreateOptionsMenu(Menu menu) {
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.main_activity, menu);
+ return true;
+}
+
+
+In the XML file, you can request a menu item to appear as an action item by declaring {@code android:showAsAction="ifRoom"} for the {@code <item>} element. This way, the menu item appears -in the Action Bar for quick access only if there is room available for it. If there's not -enough room, the item is placed the overflow menu (revealed by the menu icon on the right side -of the Action Bar).
+in the action bar for quick access only if there is room available. If there's not +enough room, the item appears in the overflow menu. -You can also declare a menu item to appear as an action item from your application code, by -calling {@link android.view.MenuItem#setShowAsAction setShowAsAction()} on the {@link -android.view.MenuItem} and passing {@link android.view.MenuItem#SHOW_AS_ACTION_IF_ROOM}.
+If your menu item supplies both a title and an icon—with the {@code android:title} and +{@code android:icon} attributes—then the action item shows only the icon by default. If you +want to display the text title, add {@code "withText"} to the {@code android:showAsAction} +attribute. For example:
-If your menu item supplies both a title and an icon, then the action item shows only -the icon by defult. If you want to include the text with the action item, add the "with -text" flag: in XML, add {@code withText} to the {@code android:showAsAction} attribute or, in -your application code, use the {@link android.view.MenuItem#SHOW_AS_ACTION_WITH_TEXT} flag when -calling {@link android.view.MenuItem#setShowAsAction setShowAsAction()}. Figure 2 shows an Action -Bar that has two action items with text and the icon for the overflow menu.
- -Here's 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">
@@ -191,58 +261,200 @@ href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource fil
</menu>
-In this case, both the {@code ifRoom} and {@code withText} flags are set, so that when this -item appears as an action item, it includes the title text along with the icon.
+Note: The {@code "withText"} value is a hint to the +action bar that the text title should appear. The action bar will show the title when possible, but +might not if an icon is available and the action bar is constrained for space.
-A menu item placed in the Action Bar triggers the same callback methods as other items in the -Options Menu. When the user selects an action item, your activity receives a call to -{@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()}, passing the -item ID.
+When the user selects an action item, your activity receives a call to +{@link android.app.Activity#onOptionsItemSelected(MenuItem) +onOptionsItemSelected()}, passing the ID supplied by the {@code android:id} attribute—the same +callback received for all items in the options menu.
-Note: If you added the menu item from a fragment, then the -respective {@link -android.app.Fragment#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} method is called -for that fragment. However the activity gets a chance to handle it first, so the system calls {@link -android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} on the activity -before calling the fragment.
+It's important that you always define {@code android:title} for each menu item—even if you +don't declare that the title appear with the action item—for three reasons:
+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 other elements in the Action Bar.
+The {@code android:icon} is always optional, but recommended. For icon design recommendations, +see the Action Bar +Icon design guidelines.
- + +You can also declare an item to "always" appear as an action item, instead of being +placed in the overflow menu when space is limited. In most cases, you should not +force an item to appear in the action bar by using the {@code "always"} value. However, you might +need an item to always appear when it provides an action view that does +not offer a default action for the overflow menu. Beware that too +many action items can create a cluttered UI and cause layout problems on devices with a narrow +screen. It's best to instead use {@code "ifRoom"} to request that an item appear in the action +bar, but allow the system to move it into the overflow menu when there's not enough room.
+ +For more information about creating the options menu that defines your action items, see the Menus developer guide.
-By default, your application icon appears in the Action Bar on the left side. It also responds -to user interaction (when the user taps it, it visually responds the same way action -items do) and it's your responsibility to do something when the user taps it.
+Figure 3. Email's Action Bar, with the -application icon on the left.
+As a general rule, all items in the options menu (let alone action items) +should have a global impact on the app, rather than affect only a small portion of the interface. +For example, if you have a multi-pane layout and one pane shows a video while another lists all +videos, the video player controls should appear within the pane containing the video (not in the +action bar), while the action bar might provide action items to share the video or save the video to +a favorites list.
+So, even before deciding whether a menu item should appear as an action item, be sure that +the item has a global scope for the current activity. If it doesn't, then you should place it +as a button in the appropriate context of the activity layout.
+The normal behavior should be for your application to return to the "home" activity or the -initial state (such as when the activity hasn't changed, but fragments have changed) when the user -taps the icon. If the user is already at home or the initial state, then you don't need to do -anything.
+You should carefully choose which items from your options menu should appear as action items by +assessing a few key traits. In general, each action item should be at least one +of the following:
-When the user taps the icon, the system calls your activity's {@link +
Example frequent actions: "New message" in the Messaging app and +"Search" in Android Market.
+Example important actions: "Add network" in Wi-Fi settings and "Switch to camera" in the +Gallery app.
+Example typical actions: "Refresh" in an email or social app, and "New contact" in the +People app.
+If you believe that more than four of your menu items can be justified as action items, then you +should carefully consider their relative level of importance and try to set no more than four as +action items (and do so using the {@code "ifRoom"} value to allow the system to put some back in the +overflow menu when space is limited on smaller screens). Even if space is available on a wide +screen, you should not create a long stream of action items that clutter the UI and appear like a +desktop toolbar, so keep the number of action items to a minimum.
+ +Additionally, the following actions should never appear as action items: Settings, Help, +Feedback, or similar. Always keep them in the overflow menu.
+ +Note: Remember that not all devices provide a dedicated hardware +button for Search, so if it's an important feature in your app, it should always appear as an +action item (and usually as the first item, especially if you offer it with an action view).
+ + + +When your application is running on Android 4.0 (API level 14) and higher, there's an extra mode +available for the action bar called "split action bar." When you enable split action bar, a separate +bar appears at the bottom of the screen to display all action items when the activity is running on +a narrow screen (such as a portrait-oriented handset). Splitting the action bar to separate +the action items ensures that a reasonable amount of space is available to display all your action +items on a narrow screen, while leaving room for navigation and title elements at the top.
+ +To enable split action bar, simply add {@code uiOptions="splitActionBarWhenNarrow"} to your +{@code <activity>} or +{@code <application>} +manifest element.
+ +Be aware that Android adjusts the action bar's appearance in a variety of ways, based on the +current screen size. Using split action bar is just one option that you can enable to allow the +action bar to further optimize the user experience for different screen sizes. In doing so, you +may also allow the action bar to collapse navigation tabs into the main action bar. That is, if you +use navigation tabs in your action bar, once the action items are +separated on a narrow screen, the navigation tabs may be able to fit into the main action bar rather +than be separated into the "stacked action bar." Specifically, if you've disabled the action bar +icon and title (with {@link android.app.ActionBar#setDisplayShowHomeEnabled +setDisplayShowHomeEnabled(false)} and {@link android.app.ActionBar#setDisplayShowTitleEnabled +setDisplayShowTitleEnabled(false)}), then the navigation tabs collapse into the main action bar, as +shown by the second device in figure 3.
+ +
+Figure 3. Mock-ups of split action bar with navigation tabs +on the left; with the app icon and title disabled on the right.
+ +Note: Although the {@link android.R.attr#uiOptions +android:uiOptions} attribute was added in Android 4.0 (API level 14), you can safely include it in +your application even if your {@code minSdkVersion} is set to +a value lower than {@code "14"} to remain compatible with older versions of Android. When running on +older versions, the system simply ignores the XML attribute because it doesn't understand it. The +only condition to including it in your manifest is that you must compile your application against a +platform version that supports API level 14 or higher. Just be sure that you don't openly use other +APIs in your application code that aren't supported by the version declared by your {@code minSdkVersion} +attribute—only XML attributes are safely ignored by older platforms.
+ + + + +By default, the system uses your application icon in the action bar, as specified by the {@code android:icon} +attribute in the {@code +<application>} or {@code +<activity>} element. However, if you also specify the {@code android:logo} +attribute, then the action bar uses the logo image instead of the icon.
+A logo should usually be wider than the icon, but should not include unnecessary text. You +should generally use a logo only when it represents your brand in a traditional format that users +recognize. A good example is the YouTube app's logo—the logo represents the expected user +brand, whereas the app's icon is a modified version that conforms to the square requirement.
+By default, your application icon appears in the action bar on the left side. If you'd like, +you can enable the icon to behave as an action item. In response to user action on the icon, your +application should do one of two things:
+ +When the user touches the icon, the system calls your activity's {@link android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} method with the {@code -android.R.id.home} ID. So, you need to add a condition to your {@link -android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} method to listen for {@code -android.R.id.home} and perform the appropriate action, such as start the home activity or pop recent -fragment transactions off the stack.
+android.R.id.home} ID. In response, you should either start the home activity or +take the user one step up in your application's structural hierarchy.If you respond to the application icon by returning to the home activity, you should include the {@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP} flag in the {@link android.content.Intent}. With this flag, if the activity you're starting already exists in the current task, then all activities on top of it are destroyed and it is brought to the front. -You should favor this approach, because going "home" is an action that's equivalent to "going +Adding this flag is often important because going "home" is an action that's equivalent to "going back" and you should usually not create a new instance of the home activity. Otherwise, you -might end up with a long stack of activities in the current task.
+might end up with a long stack of activities in the current task with multiple instances of the +home activity.For example, here's an implementation of {@link android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} that returns to the application's "home" activity:
@@ -252,7 +464,7 @@ onOptionsItemSelected()} that returns to the application's "home" activity: public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: - // app icon in Action Bar clicked; go 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); @@ -263,129 +475,153 @@ public boolean onOptionsItemSelected(MenuItem item) { } - - - -
- 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 current activity). 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 {@link android.app.ActionBar#setDisplayHomeAsUpEnabled -setDisplayHomeAsUpEnabled(true)} on your activity's {@link android.app.ActionBar}. When you do, the -system draws your application icon with an arrow indicating the up behavior, as shown in figure -4.
- -For example, here's how you can show the application icon as an "up" action:
+In case the user can enter the current activity from another application, you might also want to +add the {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag. This flag ensures that, when the +user navigates either "home" or "up", the new activity is not added to the current +task, but instead started in a task that belongs to your application. For example, if the user +starts an activity in your application through an intent invoked by another application, then +selects the action bar icon to navigate home or up, the {@link +android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP} flag starts the activity in a task that belongs to +your application (not the current task). The system either starts a new task with your new activity +as the root activity or, if an existing task exists in the background with an instance of that +activity, then that task is brought forward and the target activity receives {@link +android.app.Activity#onNewIntent onNewIntent()}. So if your activity accepts intents from other +applications (it declares any generic intent filters), you should usually add the {@link +android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag to the intent:
-@Override
-protected void onStart() {
- super.onStart();
- ActionBar actionBar = this.getActionBar();
+intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
+
+
+For more information about these flags and other back stack behaviors, read the Tasks and Back Stack +developer guide.
+ +Note: If you're using the icon to navigate to the home +activity, beware that beginning with Android 4.0 (API level 14), you must explicitly enable the +icon as an action item by calling {@link android.app.ActionBar#setHomeButtonEnabled +setHomeButtonEnabled(true)} (in previous versions, the icon was enabled as an action item by +default).
+ + + +
+ Figure 4. The Email app's standard icon +(left) and the "navigate up" icon (right). The system automatically adds the "up" indicator.
+As a supplement to traditional "back" navigation—which takes the user to the previous +screen in the task history—you can enable the action bar icon to offer "up" +navigation, which should take the user one step up in your application's structural hierarchy. For +instance, if the current screen is somewhere deep in the hierarchy of the application, touching the +app icon should navigate upward one level, to the parent of the current screen.
+ +For example, figure 5 illustrates how the BACK button behaves when the user navigates from one +application to an activity belonging to a different application (specifically, when composing an +email to a person selected from the People app).
+ +
+Figure 5. The BACK button behavior +after entering the Email app from the People (or Contacts) app.
+ +However, if the user wants to stay within the email application after composing the email, +up navigation allows the user to navigate upward in the email application, rather than go back +to the previous activity. Figure 6 illustrates this scenario, in which the user again comes into +the email application, but presses the action bar icon to navigate up, rather than back.
+ +
+Figure 6. Example behavior for UP navigation after +entering the Email app from the People app.
+ +To enable the icon for up navigation (which displays the "up" indicator next to the icon), call +{@link android.app.ActionBar#setDisplayHomeAsUpEnabled setDisplayHomeAsUpEnabled(true)} on your +{@link android.app.ActionBar}:
+ +
+protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.main);
+ ActionBar actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
+ ...
}
-Then, your activity should respond to the user tapping the icon, from the {@link -android.app.Activity#onOptionsItemSelected -onOptionsItemSelected()}, by listening for the {@code android.R.id.home} ID (as shown above). In -this case, when navigating up, it's even more important that you use the {@link -android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP} flag in the {@link android.content.Intent}, so that -you don't create a new instance of the parent activity if one already exists.
+When the user touches the icon, the system calls your activity's {@link +android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} method with the {@code +android.R.id.home} ID, as shown in the above section about Using the App Icon +for Navigation.
+ +Remember to use the {@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP} flag in the {@link +android.content.Intent}, so that you don't create a new instance of the parent activity if one +already exists. For instance, if you don't use the {@link +android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP} flag, then after navigating up, the BACK button will +actually take the user "forward", with respect to the application structure, which would be +strange.
+ +Note: If there are many paths that the user could have taken to +reach the current activity within your application, the up icon should navigate backward along the +path the user actually followed to get to the current activity.
- Figure 5. An action view with a {@link -android.widget.SearchView} widget.
+
+ Figure 7. An action bar with a collapsed action
+view for Search (top), then expanded action view with the SearchView widget (bottom).
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 {@link android.widget.SearchView} widget in the Action Bar whenever -the item is enabled as an action item.
-When adding an action view for a menu item, it's 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 {@link android.widget.SearchView} -widget. Figure 4 shows an example of the {@link android.widget.SearchView} widget in an action -view.
+An action view is a widget that appears in the action bar as a substitute for an action item's +button. For example, if you have an item in the options menu for "Search," you can add an action +view that replaces the button with a {@link android.widget.SearchView} widget, as shown in figure +7.
-The best way to declare an action view for an item is in your menu resource, using the {@code -android:actionLayout} or {@code android:actionViewClass} attribute:
+To declare an action view for an item in your menu resource, use either the {@code +android:actionLayout} or {@code android:actionViewClass} attribute to specify either a layout +resource or widget class to use, respectively. 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" />
+ android:title="@string/menu_search"
+ android:icon="@drawable/ic_menu_search"
+ android:showAsAction="ifRoom|collapseActionView"
+ android:actionViewClass="android.widget.SearchView" />
</menu>
--<?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> -
Notice that the {@code android:showAsAction} attribute also includes {@code +"collapseActionView"}. This is optional and declares that the action view should be collapsed into a +button. When the user selects the button, the action view expands. Otherwise, the action view is +visible by default and might consume valuable action bar space even when the user is not using it. +For more information, see the next section about Handling +collapsible action views.
-You must include {@code 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 {@code android:showAsAction} to {@code "always"}.
- -Now, when the menu item is displayed as an action item, it's action view appears instead of -the icon and/or title text. However, if there's 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 {@link -android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} callback method.
- -When the activity first starts, the system populates the Action Bar and overflow menu by calling -{@link android.app.Activity#onCreateOptionsMenu onCreateOptionsMenu()}. -After you've inflated your menu in this method, you can acquire elements in an action view -(perhaps in order to attach listeners) by calling {@link android.view.Menu#findItem -findItem()} with the ID of the menu item, then {@link android.view.MenuItem#getActionView} on -the returned {@link android.view.MenuItem}. For example, the search widget from the above samples is -acquired like this:
+If you need to add some event hooks to your action view, you can do so during the {@link +android.app.Activity#onCreateOptionsMenu onCreateOptionsMenu()} callback. You can acquire elements +in an action view by calling {@link android.view.Menu#findItem findItem()} with the ID of the menu +item, then call {@link android.view.MenuItem#getActionView}. For +example, the search widget from the above sample 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);
+ getMenuInflater().inflate(R.menu.options, menu);
+ SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
+ // Configure the search info and add any event listeners
+ ...
+ return super.onCreateOptionsMenu(menu);
}
@@ -393,167 +629,487 @@ public boolean onCreateOptionsMenu(Menu menu) {
href="{@docRoot}guide/topics/search/search-dialog.html">Creating a Search Interface.
+
- Figure 6. Screenshot of tabs in the -Action Bar, from the Honeycomb Gallery sample -application.
+The {@code "collapseActionView"} option was added with Android 4.0 (API level 14). However, if +your application supports older versions, you should +still declare {@code "collapseActionView"} in order to better support smaller screens. +Devices running Android 4.0 and higher will show the action view collapsed, while older versions +work as designed otherwise.
+Adding this value requires that you set your build target to Android 4.0 or higher in order to +compile. Older versions of Android ignore the {@code "collapseActionView"} value because they don't +understand it. Just be sure not to use other APIs in your source code that are not supported in the +version declared by your {@code +minSdkVersion}, unless you add the appropriate version check at runtime.
+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 {@link android.view.View} in which each {@link -android.app.Fragment} associated with a tab is displayed. Be sure the view has an ID that you -can use to reference it from your code.
+Action views allow you to provide fast access to rich actions without changing activities or +fragments, or replacing the action bar. However, it might not be appropriate to make an action view +visible by default. To preserve the action bar space (especially when running on smaller screens), +you can collapse your action view into an action item button. When the user selects the +button, the action view appears in the action bar. When collapsed, the system might place the item +into the overflow menu if you've defined {@code android:showAsAction} with {@code "ifRoom"}, but the +action view still appears in the action bar when the user selects the item. You can make your action +view collapsible by adding {@code "collapseActionView"} to the {@code android:showAsAction} +attribute, as shown in the XML above.
+ +Because the system will expand the action view when the user selects the item, so you +do not need to respond to the item in the {@link +android.app.Activity#onOptionsItemSelected onOptionsItemSelected} callback. The system still calls +{@link android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} when the user selects it, +but the system will always expand the action view unless you return {@code true} (indicating +you've handled the event instead).
+ +The system also collapses your action view when the user selects the "up" icon in the action +bar or presses the BACK button.
+ +If necessary, you can expand or collapse the action view in your own code by calling {@link +android.view.MenuItem#expandActionView()} and {@link android.view.MenuItem#collapseActionView()} on +the {@link android.view.MenuItem}.
+ +Note: Although collapsing your action view is optional, we +recommend that you always collapse your action view if it includes {@link +android.widget.SearchView}. Also be aware that some devices provide a dedicated SEARCH button and +you should expand your search action view if the user presses the SEARCH button. Simply override +your activity's {@link android.app.Activity#onKeyUp onKeyUp()} callback method, listen for the +{@link android.view.KeyEvent#KEYCODE_SEARCH} event, then call {@link +android.view.MenuItem#expandActionView()}.
+ +If you need to update your activity based on the visibility of your action view, you can receive +callbacks when it's expanded and collapsed by defining an {@link +android.view.MenuItem.OnActionExpandListener OnActionExpandListener} and registering it with {@link +android.view.MenuItem#setOnActionExpandListener setOnActionExpandListener()}. For example:
-To add tabs to the Action Bar:
-Each callback method passes the {@link android.app.ActionBar.Tab} that received the -event and a {@link android.app.FragmentTransaction} for you to perform the fragment -transactions (add or remove fragments).
-For example:
-private class MyTabListener implements ActionBar.TabListener {
- private TabContentFragment mFragment;
+@Override
+public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.options, menu);
+ MenuItem menuItem = menu.findItem(R.id.actionItem);
+ ...
- // Called to create an instance of the listener when adding a new tab
- public MyTabListener(TabContentFragment fragment) {
- mFragment = fragment;
+ menuItem.setOnActionExpandListener(new OnActionExpandListener() {
+ @Override
+ public boolean onMenuItemActionCollapse(MenuItem item) {
+ // Do something when collapsed
+ return true; // Return true to collapse action view
+ }
+
+ @Override
+ public boolean onMenuItemActionExpand(MenuItem item) {
+ // Do something when expanded
+ return true; // Return true to expand action view
+ }
+ });
+}
+
+
+
+
+
+
+ Figure 8. Screenshot from the Gallery app, with the + {@link android.widget.ShareActionProvider} submenu expanded to show share targets.
+Similar to an action view, an action provider (defined by the {@link +android.view.ActionProvider} class) replaces an action item with a customized layout, but it also +takes control of all the item's behaviors. When you declare an action provider for a menu +item in the action bar, it not only controls the appearance of the item in the action bar with a +custom layout, but also handles the default event for the menu item when it appears in the overflow +menu. It can also provide a submenu from either the action bar or the overflow menu.
+ +For example, the {@link android.widget.ShareActionProvider} is an extension of {@link +android.view.ActionProvider} that facilitates a “share" action by showing a list of available share +targets from the action bar. Instead of using a +traditional action item that invokes the {@link android.content.Intent#ACTION_SEND} intent, you can +declare an instance of {@link android.widget.ShareActionProvider} to handle an action item. This +action provider presents an action view with a drop-down list of applications that handle +the {@link android.content.Intent#ACTION_SEND} intent, even when the menu item appears in the +overflow menu. Hence, when you use an action provider such as this one, you don't +have to handle user events on the menu item.
+ +To declare an action provider for an action item, define the {@code android:actionProviderClass} +attribute for the appropriate the {@code <item>} element in your menu resource, using the +fully-qualified class name of the action provider. For example:
+ ++<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/menu_share" + android:title="@string/share" + android:showAsAction="ifRoom" + android:actionProviderClass="android.widget.ShareActionProvider" /> + ... +</menu> ++ +
In this example, the {@link android.widget.ShareActionProvider} is used as the action provider. +At this point, the action provider officially takes control of the menu item and handles both +its appearance and behavior in the action bar and its behavior in the overflow menu. You must +still provide a text title for the item to be used in the overflow menu.
+ +Although the action provider can perform the default action for the menu item when it appears in +the overflow menu, your activity (or fragment) can override that behavior by +also handling the click event from the {@link android.app.Activity#onOptionsItemSelected +onOptionsItemSelected()} callback method. If you do not handle the event in that callback, then +the action provider receives the {@link android.view.ActionProvider#onPerformDefaultAction()} +callback to handle the event. However, if the action provider provides a submenu, then your +activity will not receive the {@link android.app.Activity#onOptionsItemSelected +onOptionsItemSelected()} callback, because the submenu is shown instead of invoking the default +menu item behavior when selected.
+ + + +If you want to provide a "share" action in your action bar by leveraging other applications +installed on the device (for example, to share a photo using a messaging or social app), then using +{@link android.widget.ShareActionProvider} is an effective way to do so, rather than adding an +action item that invokes the {@link android.content.Intent#ACTION_SEND} intent. When +you use {@link android.widget.ShareActionProvider} for an action item, it presents an action view +with a drop-down list of applications that handle the {@link android.content.Intent#ACTION_SEND} +intent (as shown in figure 8).
+ +All the logic for creating the submenu, populating it with share targets, and handling click +events (including when the item appears in the overflow menu) is implemented by the {@link +android.widget.ShareActionProvider}—the only code you need to write is to declare the action +provider for the menu item and specify the share intent.
+ +By default, the {@link android.widget.ShareActionProvider} retains a ranking for each +share target based on how often the user selects each one. The share targets used more frequently +appear at the top of the drop-down list and the target used most often appears directly in the +action bar as the default share target. By default, the ranking information is +saved in a private file with a name specified by {@link +android.widget.ShareActionProvider#DEFAULT_SHARE_HISTORY_FILE_NAME}. If you use the {@link +android.widget.ShareActionProvider} or an extension of it for only one type of action, then you +should continue to use this default history file and there's nothing you need to do. However, if you +use {@link android.widget.ShareActionProvider} or an extension of it for multiple actions with +semantically different meanings, then each {@link android.widget.ShareActionProvider} should specify +its own history file in order to maintain its own history. To specify a +different history file for the {@link android.widget.ShareActionProvider}, call {@link +android.widget.ShareActionProvider#setShareHistoryFileName setShareHistoryFileName()} and provide +an XML file name (for example, {@code "custom_share_history.xml"}).
+ +Note: Although the {@link android.widget.ShareActionProvider} ranks +share targets based on frequency of use, the behavior is extensible and extensions of {@link +android.widget.ShareActionProvider} can perform different behaviors and ranking based on the history +file (if appropriate).
+ +To add {@link android.widget.ShareActionProvider}, simply define the {@code +android:actionProviderClass} attribute with {@code "android.widget.ShareActionProvider"}, as shown +in the XML example above. The only thing left to do is define +the {@link android.content.Intent} you want to use for sharing. To do so, you must call {@link +android.view.MenuItem#getActionProvider} to retrieve the {@link android.widget.ShareActionProvider} +that's associated with a {@link android.view.MenuItem}, then call {@link +android.widget.ShareActionProvider#setShareIntent setShareIntent()}.
+ +If the format for the share intent depends on the selected item or other variables that change +during the activity lifecycle, you should save the {@link android.widget.ShareActionProvider} in a +member field and update it by calling {@link android.widget.ShareActionProvider#setShareIntent +setShareIntent()} as necessary. For example:
+ +
+private ShareActionProvider mShareActionProvider;
+...
+
+@Override
+public boolean onCreateOptionsMenu(Menu menu) {
+ mShareActionProvider = (ShareActionProvider) menu.findItem(R.id.menu_share).getActionProvider();
+
+ // If you use more than one ShareActionProvider, each for a different action,
+ // use the following line to specify a unique history file for each one.
+ // mShareActionProvider.setShareHistoryFileName("custom_share_history.xml");
+
+ // Set the default share intent
+ mShareActionProvider.setShareIntent(getDefaultShareIntent());
+
+ return true;
+}
+// When you need to update the share intent somewhere else in the app, call
+// mShareActionProvider.{@link android.widget.ShareActionProvider#setShareIntent setShareIntent()}
+
+
+The {@link android.widget.ShareActionProvider} now handles all user interaction with the item and +you do not need to handle click events from the {@link +android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} callback method.
+ +For a sample using the share action provider, see +ActionBarActionProviderActivity. + + + +
When you want to create an action view that has dynamic behaviors and a default action in the +overflow menu, extending {@link android.view.ActionProvider} to define those behaviors is a good +solution. Creating your own action provider offers you an organized and reusable component, rather +than handling the various action item transformations and behaviors in your fragment or activity +code. As shown in the previous section, Android provides one implementation of {@link +android.view.ActionProvider} for share actions: the {@link android.widget.ShareActionProvider}.
+ +To create your own, simply extend the {@link android.view.ActionProvider} class and implement +its callback methods as appropriate. Most importantly, you should implement the following:
+ +
+public View onCreateActionView() {
+ // Inflate the action view to be shown on the action bar.
+ LayoutInflater layoutInflater = LayoutInflater.from(mContext);
+ View view = layoutInflater.inflate(R.layout.action_provider, null);
+ ImageButton button = (ImageButton) view.findViewById(R.id.button);
+ button.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // Do something...
+ }
+ });
+ return view;
+}
+
+However, if your action provider provides a submenu, through the {@link +android.view.ActionProvider#onPrepareSubMenu onPrepareSubMenu()} callback, then the submenu +appears even when the menu item is in the overflow menu. Thus, {@link +android.view.ActionProvider#onPerformDefaultAction()} is never called when there is a +submenu.
+Note: An activity or a fragment that implements {@link +android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} can override the action +provider's default behavior by handling the item-selected event (and returning true), in which +case, the system does not call {@link android.view.ActionProvider#onPerformDefaultAction()}.
+For an example extension of {@link android.view.ActionProvider}, see ActionBarSettingsActionProviderActivity.
+ + + + +
+ Figure 9. Screenshot of action bar tabs from the Honeycomb Gallery app.
+
+ Figure 10. Screenshot of tabs in the stacked action +bar on a narrow screen.
+When you want to provide navigation tabs in an activity, using the action bar's +tabs is a great option (instead of using {@link android.widget.TabWidget}), because the +system adapts the action bar tabs for different screen sizes—placing them in the main action +bar when the screen is sufficiently wide, or in a separate bar (known as the "stacked action bar") +when the screen is too narrow, as shown in figures 9 and 10.
+ +To switch between fragments using the tabs, you must perform a fragment +transaction each time a tab is selected. If you're not familiar with how to change fragments +using {@link android.app.FragmentTransaction}, first read the Fragments developer guide.
+ +To get started, your layout must include a {@link android.view.ViewGroup} in which you place each +{@link android.app.Fragment} associated with a tab. Be sure the {@link android.view.ViewGroup} has a +resource ID so you can reference it from your tab-swapping code. Alternatively, if the tab content +will fill the activity layout (excluding the action bar), then your activity doesn't need a layout +at all (you don't even need to call {@link android.app.Activity#setContentView +setContentView()}). Instead, you can place each fragment in the default root {@link +android.view.ViewGroup}, which you can refer to with the {@code android.R.id.content} ID (you can +see this ID used in the sample code below, during fragment transactions).
+ +Once you determine where the fragments appear in the layout, the basic procedure to add tabs +is:
+When looking at the {@link android.app.ActionBar.TabListener} interface, notice that the +callback methods provide only the {@link android.app.ActionBar.Tab} that was selected and a {@link +android.app.FragmentTransaction} for you to perform fragment transactions—it doesn't say +anything about what fragment you should swap in or out. Thus, you must define your own association +between each {@link android.app.ActionBar.Tab} and the appropriate {@link android.app.Fragment} that +it represents (in order to perform the appropriate fragment transaction). There are several ways you +can define the association, depending on your design. In the example below, the {@link +android.app.ActionBar.TabListener} implementation provides a constructor such that each new tab uses +its own instance of the listener. Each instance of the listener defines several fields that are +necessary to later perform a transaction on the appropriate fragment.
+ +For example, here's how you might implement the {@link android.app.ActionBar.TabListener} +such that each tab uses its own instance of the listener:
+
+public static class TabListener<T extends Fragment> implements ActionBar.TabListener {
+ private Fragment mFragment;
+ private final Activity mActivity;
+ private final String mTag;
+ private final Class<T> mClass;
+
+ /** Constructor used each time a new tab is created.
+ * @param activity The host Activity, used to instantiate the fragment
+ * @param tag The identifier tag for the fragment
+ * @param clz The fragment's Class, used to instantiate the fragment
+ */
+ public TabListener(Activity activity, String tag, Class<T> clz) {
+ mActivity = activity;
+ mTag = tag;
+ mClass = clz;
}
+ /* The following are each of the {@link android.app.ActionBar.TabListener} callbacks */
+
public void onTabSelected(Tab tab, FragmentTransaction ft) {
- ft.add(R.id.fragment_content, mFragment, null);
+ // Check if the fragment is already initialized
+ if (mFragment == null) {
+ // If not, instantiate and add it to the activity
+ mFragment = Fragment.instantiate(mActivity, mClass.getName());
+ ft.add(android.R.id.content, mFragment, mTag);
+ } else {
+ // If it exists, simply attach it in order to show it
+ ft.attach(mFragment);
+ }
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
- ft.remove(mFragment);
+ if (mFragment != null) {
+ // Detach the fragment, because another one is being attached
+ ft.detach(mFragment);
+ }
}
public void onTabReselected(Tab tab, FragmentTransaction ft) {
- // do nothing
+ // User selected the already selected tab. Usually do nothing.
}
-
}
- This implementation of {@link android.app.ActionBar.TabListener} adds a constructor -that saves the {@link android.app.Fragment} associated with a tab so that each callback -can add or remove that fragment.
-Tip: These methods return the same {@link -android.app.ActionBar.Tab} instance, so you can chain the calls together.
For example, the following code combines steps 2 - 5 to create two tabs and add them to -the Action Bar:
+ +Caution: You must not call {@link +android.app.FragmentTransaction#commit} for the fragment transaction in each of these +callbacks—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.
+ +In this example, the listener simply attaches ({@link android.app.FragmentTransaction#attach +attach()}) a fragment to the activity layout—or if not instantiated, creates the fragment and +adds ({@link android.app.FragmentTransaction#add add()}) it to the layout (as a child of the {@code +android.R.id.content} view group)—when the respective tab is selected, and detaches ({@link +android.app.FragmentTransaction#detach detach()}) it when the tab is unselected.
+ +The {@link android.app.ActionBar.TabListener} implementation is the bulk of the work. All that +remains is to create each {@link android.app.ActionBar.Tab} and add it to the {@link +android.app.ActionBar}. Additionally, you must call {@link +android.app.ActionBar#setNavigationMode(int) setNavigationMode(NAVIGATION_MODE_TABS)} to make the +tabs visible. You might also want to disable the activity title by calling {@link +android.app.ActionBar#setDisplayShowTitleEnabled setDisplayShowTitleEnabled(false)} if the tab +titles actually indicate the current view.
+ +For example, the following code adds two tabs using the listener defined above:
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
+ // Notice that setContentView() is not used, because we use the root
+ // android.R.id.content as the container for each fragment
- // setup Action Bar for tabs
- final ActionBar actionBar = getActionBar();
+ // setup action bar for tabs
+ 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();
- // 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)));
+ Tab tab = actionBar.newTab()
+ .setText(R.string.artist)
+ .setTabListener(new TabListener<ArtistFragment>(
+ this, "artist", ArtistFragment.class));
+ actionBar.addTab(tab);
- Fragment albumsFragment = new AlbumsFragment();
- actionBar.addTab(actionBar.newTab().setText(R.string.tab_albums)
- .setTabListener(new TabListener(albumsFragment)));
+ tab = actionBar.newTab()
+ .setText(R.string.album)
+ .setTabListener(new TabListener<AlbumFragment>(
+ this, "album", AlbumFragment.class));
+ actionBar.addTab(tab);
}
-All the behaviors that occur when a tab is selected must be defined by your {@link -android.app.ActionBar.TabListener} callback methods. When a tab is selected, it receives a call to -{@link android.app.ActionBar.TabListener#onTabSelected onTabSelected()} and that's where you should -add the appropriate fragment to the designated view in your layout, using {@link -android.app.FragmentTransaction#add add()} with the provided {@link -android.app.FragmentTransaction}. Likewise, when a tab is deselected (because another tab becomes -selected), you should remove that fragment from the layout, using {@link -android.app.FragmentTransaction#remove remove()}.
+Note: The above implementation for {@link +android.app.ActionBar.TabListener} is one of several possible techniques. You can see more of +this style in the API Demos app.
-Caution: You must not call {@link -android.app.FragmentTransaction#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 it's time to save the +
If your activity stops, you should retain the currently selected tab with the saved instance +state so you can open the appropriate tab when the user returns. When it's time to save the state, you can query the currently selected tab with {@link android.app.ActionBar#getSelectedNavigationIndex()}. This returns the index position of the selected tab.
-Caution: It's 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.
+Caution: It's important that you save the state of each fragment +as necessary, so that when users switch fragments with the tabs and then return to a previous +fragment, it looks the way it did when they left. For information about saving the state of your +fragment, see the Fragments +developer guide.
+Note: In some cases, the Android system will show your action +bar tabs as a drop-down list in order to ensure the best fit in the action bar.
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 user's account.
+As another mode of navigation (or filtering) within your activity, the action bar offers a +built in drop-down list. For example, the drop-down list can offer different modes by which content +in the activity is sorted.
-Here's a quick list of steps to enable drop-down navigation:
+The basic procedure to enable drop-down navigation is:
ActionBar actionBar = getActionBar(); @@ -563,13 +1119,13 @@ actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); android.app.Activity#onCreate onCreate()} method.
actionBar.setListNavigationCallbacks(mSpinnerAdapter, mNavigationCallback);
This method takes your {@link android.widget.SpinnerAdapter} and {@link -android.app.ActionBar.OnNavigationListener}. More about these next.
+android.app.ActionBar.OnNavigationListener}.{@link android.widget.SpinnerAdapter} is an adapter that provides data for a spinner widget, -such as the drop-down list in the Action Bar. {@link android.widget.SpinnerAdapter} is an interface +such as the drop-down list in the action bar. {@link android.widget.SpinnerAdapter} is an interface that you can implement, but Android includes some useful implementations that you can extend, such as {@link android.widget.ArrayAdapter} and {@link android.widget.SimpleCursorAdapter}. For example, here's an easy way to create a {@link @@ -713,140 +1269,199 @@ public class ListContentFragment extends Fragment {
The Action Bar is the heading for your application and a primary interaction point for users, -so you might want to modify some of its design in order to make it feel more integrated with your -application design. There are several ways you can do this if you wish.
+If you've implemented a custom design for the widgets in your application, you might +also want to redesign some of the action bar to match your app design. To do so, you need to use +Android's style and theme framework to restyle the action +bar using special style properties.
-For simple modifications to the {@link android.app.ActionBar}, you can use the following -methods:
+ +Note: In order for background images to change appearance +depending on the current button state (selected, pressed, unselected), the drawable resource you use +must be a state +list drawable.
+ +Caution: For all background drawables you provide, be sure to use Nine-Patch drawables to allow +stretching. The Nine-Patch image should be smaller than 40px tall and 30px wide (for the mdpi asset).
+ + +For more complex customizations, you can use Android's style and theme framework to restyle your Action -Bar in several ways.
- -The Action Bar has two standard themes, "dark" and "light". The dark theme is applied with -the default holographic theme, as specified by the {@link android.R.style#Theme_Holo Theme.Holo} -theme. If you want a white background with dark text, instead, you can apply the {@link -android.R.style#Theme_Holo_Light Theme.Holo.Light} theme to the activity in the manifest file. For -example:
+Normally, the action bar requires its own space on the screen and your activity layout fills in +what's left over. When the action bar is in overlay mode, your activity layout uses all the +available space and the system draws the action bar on top. Overlay mode can be useful if you want +your content to keep a fixed size and position when the action bar is hidden and shown. You might +also like to use it purely as a visual effect, because you can use a semi-transparent background +for the action bar so the user can still see some of your activity layout behind the action +bar.
+Note: The {@link android.R.style#Theme_Holo Holo} theme families +draw the action bar with a semi-transparent background by default. However, you can modify it with +your own styles and the {@link android.R.style#Theme_DeviceDefault DeviceDefault} theme on +different devices might use an opaque background by default.
+When overlay mode is enabled, your activity layout has no awareness of the action bar laying on +top of it. So, you must be careful not to place any important information or UI components in the +area overlayed by the action bar. If appropriate, you can refer to the platform's value for {@link +android.R.attr#actionBarSize} to determine the height of the action bar, by referencing it +in your XML layout. For example:
-<activity android:name=".ExampleActivity" - android:theme="@android:style/Theme.Holo.Light" /> +<SomeView + ... + android:layout_marginTop="?android:attr/actionBarSize" />- -
For more control, you can override either the {@link android.R.style#Theme_Holo -Theme.Holo} or {@link android.R.style#Theme_Holo_Light Theme.Holo.Light} theme and apply custom -styles to certain aspects of the Action Bar. Some of the Action Bar properties you can customize -include the following:
- -You can also retrieve the action bar height at runtime with {@link +android.app.ActionBar#getHeight()}. This reflects the height of the action bar at the time it's +called, which might not include the stacked action bar (due to navigation tabs) if called during early +activity lifecycle methods. To see how you can determine the total height at runtime, including the +stacked action bar, see the {@code TitlesFragment} class in the Honeycomb Gallery sample app.
+For example, here's a resource file that defines a custom theme for the Action Bar, based on -the standard {@link android.R.style#Theme_Holo Theme.Holo} theme:
+ +For example, here's a file that defines a few custom styles for the action bar:
<?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 name="CustomActivityTheme" parent="@android:style/Theme.Holo">
+ Â <item name="android:actionBarTabTextStyle">@style/CustomTabTextStyle</item>
+ Â <item name="android:actionBarDivider">@drawable/ab_divider</item>
+ <item name="android:actionBarItemBackground">@drawable/ab_item_background</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 for the action bar tab text -->
+ <style name="CustomTabTextStyle">
+ <item name="android:textColor">#2456c2</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 be certain that your theme declares a parent theme, from which it -inherits all styles not explicitly declared in your theme.
+Note: Be certain that your theme declares a parent theme in the +{@code <style>} tag, from which it inherits all styles not explicitly declared by your theme. +When modifying the action bar, using a parent theme is important so that you can simply override the +action bar styles you want to change without re-implementing the styles you want to leave alone +(such as text appearance or padding in action items).
You can apply your custom theme to the entire application or to individual activities in your -manifest file, like this:
+manifest file like this:
-<application android:theme="@style/CustomActionBar"
+<application android:theme="@style/CustomActivityTheme"
... />
-Additionally, if you want to create a custom theme for your activity that removes the Action -Bar completely, use the following style attributes:
- -For more information about using themes in your application, read For more information about using style and theme resources in your application, read Styles and Themes.
+If you need more advanced styling for the action bar than is available with the +properties above, you can include {@link android.R.attr#actionBarStyle android:actionBarStyle} and +{@link android.R.attr#actionBarSplitStyle android:actionBarSplitStyle} in your activity's theme. +Each of these specifies another style that can define various properties for the action bar, +including different backgrounds with {@link android.R.attr#background android:background}, {@link +android.R.attr#backgroundSplit android:backgroundSplit}, and {@link android.R.attr#backgroundStacked +android:backgroundStacked}. If you override these action bar styles, be sure that you define a +parent action bar style such as {@link android.R.style#Widget_Holo_ActionBar +Widget.Holo.ActionBar}.
+ +For example, if you want to change the action bar's background, you could use the following +styles:
+ ++<?xml version="1.0" encoding="utf-8"?> +<resources> + <!-- the theme applied to the application or activity --> + <style name="CustomActivityTheme" parent="@android:style/Theme.Holo"> + Â <item name="android:actionBarTabTextStyle">@style/customTabTextStyle</item> + <!-- other activity and action bar styles here --> + </style> + + <!-- style for the action bar, simply to change the background --> + <style parent="@android:style/Widget.Holo.ActionBar"> + <item name="android:background">@drawable/ab_background</item> + <item name="android:backgroundSplit">@drawable/ab_background</item> + </style> +</resources> ++ + + diff --git a/docs/html/images/ui/actionbar-actionview.png b/docs/html/images/ui/actionbar-actionview.png index cc18f9b764e8c7cca752dc93b20c385e001902d3..9103dc41745dd32fabe8e5d18ea6be61354a1494 100644 GIT binary patch literal 7430 zcmYLO1yodB*9HZonV~yHK!y|$UWXbOLb_+@lv2V$7$gM=VF+my1_9|oLXZXl>26fI zyN1qx-tS-E|F3o9+;iis^X$E!XYX@A=xVD{kTR3v;o(uJt10W_;o+Cy+Tz4SxZ@Jl zF|Gp-AEB=b!TUDIx{13W@lb;!@bJiJ{@wBMK4mcCIv;qcYe66UC1u9P=P=x8Nyc?C zc|l=bO75>-Ik
b~`&e^W;sL8Ib1)S?hXxpH364`(H5d{u6Iz zP=7bO&5yPH0X4t7YD zoOK`;*SyP*XKrrpy{NJ1+@|0ST9+xEE&$CF4cdtY1Xv-=oyEI zp+}plI4MWNkP?p0g1%vc6e5dyxXIS5M0!zMS&yXIRvc1ry>pY5oqgIl6%MT`j-VZb z_lVbY`XUWqz8vbkT1#;*xIIZ!+@3SF-kB~{p?YQhkqa^Z{rgAA80CDu`5*uS`7-{s zl3|`MF1Bku!EwqgsP1D0!ohWQ#p{0%P=>A147P9u`s1fpsStB)vMp^+u?x(gqPov6 zmg=8lrY8UJ?=bNlXA4E%uLKt<+_p$=2`!%x42-1F 4u>ngEKMi`% zrVicyU5}iEZ2>Sd4Cl8u->oe4_}u0WWm23(Dn0~z_REJ}3cJqpztCFE-oHexjwLch zjLwv+%ey*#`&U!DSOM16CF9YxUpe4PBkP{ixHCeY{`!6#9XBW3zxY7cD3-&XM0dZB z!@Eh*6LbjDZ7qsvlcs;x>^l98R!{NHFO&<0syb%V4BI3tUe9+dV#(J&YkC`=3S9QD z6N#7<4*l1F%v%>LMict``>%wZPplF(h5EP!2X`V#^QF95w?@*=haksmy rUTELqx+h8ydmUETA)byzcD%NXQg;5WR>qvc9X{|*coC8pw zad&f7UR&GkHPII?cREA{Bo(R7tVV?)EM#Lig~}HI9e}st;l%d**-XJ0FOpwgMtVlx z(CO&tq|!^nwIVldIQ6ubZ1HK91-RLqnW@H5Sq`hPjQzmde+_vqC>gjmr`zn4y43Eqt2 zVl-k1CcjD NLF9d?{W5Cgp?)_b6W+nkqV&nFYLu9^epdg*3 z$6?E{%?DZ5s0D%?cs$6pHX8|5NUX^>-JZ>MOG;H#nW(4zIyUx20}Tzr#a%sQXn(^$ zwi2|J_M>e=ohe+^)s-*w^6)iKA^0s?M# |qR>%J+Va!UssQn#-L6y`d6Pdr;le^HSqr_nbG|7Qh8q z9E5wDH3efWyMxE)u?tJ&8^^bDV@7&%*$+weTDP)D+Nyi+ ci6>@`b%SD5%QVoH|8Rl?B`#NR8(5O%Z*93D+KSbcJ7qr(^mL6-v?j6QDq%i z=)d=WX$<-OYp&?es?V5!+geY)QI)RuZvd3PNr#5GN%Z$_eZ14Mz9v=tGe9im|LY}} z>97rG{1ab#9qS8nOw85q8R;DnzkYLbW3hTPGO=qEh%3e9 U BoKSjKpt0g zbmRfxXHx(c+K_Ubq@QoJo`N#Sc5Ecj0ey)XS5w5FjYNPjG1i$j?$*{dlr=SFI2MQJ z{61I+bQU3|l>}KbHo4SN!!6aQ1h~50Uvq2iAI4-7C~m=Jiz4rXfsO>=*$Y;oX}zIW zAx$yAe*Nk>yP0c@7>>avFl%+8C|66{JX~z1mk-Ix<}>v DyXK%UNS&!+%ZKwAl Q>&0A+PJnEwEy zbzmpm0OoEF9Tm5taT!YhH2~-Xb|+zD#-`wB9joN-!6QZ3Zmr!sgoK`Sls__Ifv+Ux z6|nZ+xh3N=g{3DlhP=^W{|rRL1ROH YqKAbd1^}l>g $E&E5RXUg%9 zW3le<*M0_XZ>V$Am~86Q%!{Y}e(1YT4u|AGUM~k&aqLOajd{QCX*GeEk08(eWsl`y zx^~MFfCh9d$Iw{#rR9n{qQAd{OySqT0iZ;LuT{@K+=OhNO1V4-&5EO5`Eq4=#dY^Z zQq|U$)uJxveu4qgZTqlwgD!4=NYod{qILVx5xu+XfVv-8&C1R##d!%3lgVd+r1+F; zpS|h1gwjL`yY|k}J$@raIo7Cq^9M&^>O((h3Il
=^JhY+Wm-pU_jdK2KkIv}^)U>V8P(5*z^6uk4V zW!KfA%IddMO@%3)=vcZH*E& z)-v~%N=2NT3P#`=Qq+&3#f zLE5!6tn~FnIan()0uFepFi-9&3FY9=X8i7kia>=r)?*T%p+H%3Ky6Gjk_oRK_4ewg zmplOY_pf0Mqd<#aC-RtkC`mOYAt8Y=%@((f+Hz51D~b?`vXPaTE3c(72mirfR9M*L zEghNwWrMI8KW^({ef~l=lTP7MOvu`qraU=Hos%J1ir_+j@& QL?BulftUu^yRa>jTbtXfOgJ^zCr1WuE0Ma$(^}(kAW9|rSHfNhW92VIj z^zM1}aBX*(!;34%iM97G0kRf#Sn@U9#FZ`Dq-rsub%Z(rV5730#J=t_$uG14<}8=! zu(iW}C83cbifvrK9`!0Ji*yFW09@b-kJX*wIiluAOtd47Y)-7l{^8Gdrdu0{!XwlZ z9ptnp@jrq@=f9Fnd6GM3i|8iQ?za{mqUXypG$F$8+ivYhJn#o7oHgdv!*<8>`6AZ$ zKap>>spSGH-^nIH5Bj<=kEVHD5? *?3#kUj;?Kwul7!QibSI(7?ERjo1 <6J7LQQy5A)1e@Kc=FEb?4GcpnyKN))|Kkeigt_yo48JvP^` zl6~4t{!*OPsy^;yWr%r2_iZ(n!dxONk3N=x*o*l6-Ok!a6d(g9{Aa(f2X(PkO#eDY z8mOPs<6=d^!H?N^)q>v6e-R|vG9xOOy}#{-*17L^yh~pyzF48$`*Nok7^&&Qv>f}b zNF~oj_bD3pnH65|>H1{K#`#Uh&RDxw<%ae>VYi2au{6{Yr4;jTMH@407R8j4u7Ah7 zW14-nzx4Q_cz+C!DV$@dm!|$8S)njG_XdO=(^pMb)`ut9+81@>m3V!9?csPK4OL+# zvANirS=F7UImu~qqK@gS|KBeA@S(+;87eZA(m^GlXvajqV9i(u3KdnFm=x4VKjp^( z;q^BimcL>*#TZ=BS=`u3i8AM}HvYU{sEl2C0#L(+G5(Xo{}aytQ_=qu&i|*P|G#jq cB=~@vlghZqm@|n6-V|VHf^=0Ilx<@E51^Yf%K!iX diff --git a/docs/html/images/ui/actionbar-logo.png b/docs/html/images/ui/actionbar-logo.png index df914bcf3d6e572a9099e9c07f4c59d5744ecc65..c62b3e211492affa36332d95c74a75cd4b0c0153 100644 GIT binary patch literal 8154 zcmV<0A0^<4P) Px#32;bRa{vGf6951U69E94oEQKA00(qQO+^RW3L6z3A^SkUX#fBK8FWQhbVF}# zZDnqB07G(RVRU6=Aa`kWXdp*PO;A^X4i^9bA4f? C z3}4~;Lv$sCPncuaXS$i|FphV-CwS$W?yH{$?f02UH1IT!cLzz@ph4Z{tNTWVy$;iA zcgkGTWI;xKrk^%GY~$U2+NGZ)^_#HYjf^71pc}gr=b8o!GE5n!KiAD@hh@AOr9t~y zk8w2At<-iex49031?m1=nrRNxcy}C_G0n{Wir|d57UQhbG>$i~Fv}}f8d}_ppEZr+ z-Si&@`5==B&me5qZQ}0axu(SjnIs@{SjW5L#Di~znVzP(rpX8CNBeQ0%3&Gb D)5qClTokJKEB6-^fO0;%+^7|X@ey8PMK>Og=L)ghr!cn z9`6qN&?u}nECYEn4>HbNf139-%@AuCG#Qj=yPf0v`NuEy{r6aq?ul+DMApv&O*&VH zK#0JQGJ==#zNQ&|jY nb@>q-wBh_NSF<^|KYC$1m z9O@VvL5S%Ssk-_5nm!+7(tOak&pgTa?)A3{t`Txr92=l&k(l0MK-J=?l5rw>H^WYP z-_HBLjkQ>s21_HIGf=EXuxZADf&@5fQHhJkNG%u=`EDALbqra@rQ%ycs~Aay9YoUi zkiMt(`_mY{y%hp8`S@;n%SdNDp<_O#w^55Ch=~A!YZ50wuvQTQa;~B3xYT@$T1Cd9 zckIUs0~P2{h?RcWTZ8ko^{VQ0+;l%)RE;2&YlLMNX7Euph%wOu#B+%;7~{0&NM4H~ z%sLsiJZOd%gT&uWkF(#pKd}=*%4v>V-OO`G )4?-hgdk|LS$cp#Uyn#I5?=OfxxF1GSj5l_pcy`kQ}|t+Fb5`O71ToRC=?$A z^8ye?5-ujzBng5{<65UnKoTvb@qZS x4i(!uc31fB9ccnM8&i$hIS(&A=db&M_np5 zidc$bu;lVCWG(DH3*MzT1)!19kq{FILGu^T%p({H`vz X;M-F%fJHeFy|RX}{;pAd-RY??wC|1~j5;i& L_Jf$F09AD7xs(EIFTS<{F@j)G@ezq5m}ty14oW74 z8ffv0rsyqcdgnp&@i;XdUpsa!)+h}#&c5`4X1L`yX!J}L2yKe_ok%li{IHVpIm7|e z1lL0T1UmCtBy(5vo_87Qe+=FY2xDttZC7wHWoe>J6i7CD77J?4*om%w&p2%sq~H6- z7#fWRp67Ka&_bcmAvB%tqO=jQ)s*sz=q+?1 k@R?_xVPj*1OeRCK+2rKOlf3@*ukV565=Wsl3?uklT!GR$gh7morGHi|QNX4O zbN8bwAA-5}gINR`F(vb8a0S`>7qI;sP_IMib_IQ;bM7#N>@v)+z|M874dd|tc)UF_ ziZ#q}86-@-8py$Q7h&lvm;$hY+Su`q9jRUhH6Rsa@e%Y@{}OSIp!I)))czA1Zbo?1 zy$cHON0&Z@%)Ab+{5)D|fHjecrjz3(aZT`GHjkKdxcl>j(n+#OTN_Pt($IBXE?>UP z_VzZ}Y!+3eP$+QUefLGBK&b-4gzm<1F}W33IRn0cu1D+MN@n$^x0o_4KZ>6CawJ@} ze+~8j0(L7Rock&${xq!oeaJt6TzvwqCD1EYbgDg$J~Uvqh;R XNu_q9B1vcJ` z>^}+lw<60Qfb8ocjS^gj%5TB$*TKCX=05~;{|@T^8?iHOVUSkt7Hs_e2&j+KD3i4% z>`Z~6Pwao#zo*e^q?z3q!_})-DVNLSayfk8XMTR3lP6EMEJu1x)GCBcsMTPh4g_s_ zYoY~HL3xcJnHnIQLDv2ON*y*o4%P1?GjE5LzXsWJpgshbVE;Ff(wD$}0A2hrviI9) z<5{qI#Ku( B3vx!&UWw*53DnU4ivbfWo_Ox Y1Z+M&L;N9g+ Hm>QOMs1l84&25W4^?Paw`5-1tk- z_#Wg|;pp2y_oK4t<{sD`#9eFUTv{aysX#~cmC{N-5(=(ZmKSHS^)M#5OugSRPL%S6 z7ha%VuanE=@H~$bCr)tU#EF)$bU-U>DP|pJjbiIToV!ZsYfuf4uyg67(vsMu%sdn& ziL2iN?t<07hf+m0-;Xvfqs7z6>N`Qp5cp_g3(+!~xhwKltwO7KRbsL$qS`8V5e%q< zYm}9RBDNMriqnzNQLJtzn53yeH{3GD5C#E~EpX)6DrWBn5>|jFIQhurg`IJXmj4k8 z5czw6eQ3OhI(H#6Z-M$Z(Y@~=^(@RQkONzRpc$ES8?-~lX?T^sWlJ0&03^W8`W(IM zDBjFGn-|v+YjItJwc|(arY)16$z<5t+T!~4>tr$+thMBFInJIv+qdDjh!6w;*}?)x zkIbRl>llA8g49lo7D6RSIVCzug~%Tj7tNkP?G`k)kj%Z1I|r37!ru20FBjEf0oXDc z28eG_4dVnNEws>r(g~Ea($dQ!O)|MAM~|#g&lcIZcs&XqV@6i?nl$rwe|Qkw>i+4R zT&dL>Y*Z}%(kU{ h{#XcGy;I1y+d*nlRe*Faf`zQ giKk^#2{vu}!or11mr!&aq966uZ1 zY=DLpq%sFvZ=sQWoXzras $>>9&*I`Dr%#_A zm{d#igje@i_bvI{J6UvpnB30Sp!Q{qzl-E&K^;_s&cX+)k!6q^NDln%nBG4GxnGMc z(cE8*Re280D9rt6G*9h0@FM}yRPAb%$yYRNKqU)X@1&afE8Hk8P_MV?-EY52zr3D% zkgg!3t_Y?W)P~e*6>5!H7Uw@n@!VU;Uj9{d^LKEZJxpOCGQkNV3PPlD8CU@KF0}kV zkey$HBYzt?`L80)Quy=WKMiw_gS!gF_rm^fLh0Mk%*XR-t8fAJ2>k##@+i$?A7oE{ zjIFJJz}v@hNG;akEmlmzx-Y!&LPv?onKNg|=ktB7horV6*d*6s18UVh>Wu;mi%&3n z|69pi`3k!6+qjt!nVCn!7zP=G`aXEq5VM9lN26lH(r+LupMX=}0Bs_<2f=?57Cw&T zA3^hv!R{B3^0Uy)NAo4nN`SCR5E{(dyJ#Ny044chcDCw-ei_G+7QID!QkMPmL6hV; z#(O`Vd@~qP)YjN7)u`rQ$Kq?hL}B}PXnyarIHjk_6f%fA6Wz2AT6qp3L>JzTl>QsK z{w0Jay7V|=j>7h5p!R#P_)AcHJM4Z9u73{QZ$MxoY^wlGY!DFUUIq7li0aDEaAPk^ ztyIDoi!nm7Q*Bh)#bFSdN~J=%Tqcvr5Cj3mVv(h#rIuqpTv@gYK8+!w_jZ+P;Sm;J z`(_Hq{{!Bid=97d44D}RGBaQe_zL^az%c_0?}FVwL|^>ph~0*T_d~c38@~+RQ?U4p zP ?+AaV7Cf^8Cp7F)O ws>nKNhZXkkcOiFCED@B2Lc^wVr@ZIR7p@qM3j z=gx8V?AcavV!ul7TCGZ>5wNhZ+@mOM7=Upp%rCOwmdR~?li- >)+4V#!Qdi%aly f<#IjM6hB7|Xp=lSGvGhGteZUpAl zYgGLi?2)&TJN*|3J@9ufKy?=<=OE2LM2q*s^4~z_UJc@)nnj#N$i4;&Z-yg32jxrX z=JQBBgIFP~mhrqC;mW(P5B_7yt3S)NEkk9054BB<>D*B!0%2(J{U)=sGx7Vwucf7> zJ6b??c6RzI!%QYaKA&e}W25z6xm;#tWrdlUnGQxu3ybgj_ +e>eeXy1?5s8jKB z=+U>4J^c=}>Eds{0Od`boI#rZ3+7)3OFxgyJpj%em?g-bf|*B RfRT@uy7VpyUQm9_R(T~F2e+!mAh!)=)XX67P zANef)1-SMNBv7 ldlymRWxI z(-iOfX}s@z2Jh1EGgG~Ut3L;)J_3s$fD?}aAyJ)G7R5(uPa|O+e2cB`(Wn{1wfB&H z=u=b+53zo|M5B5E;~I=e$99G`y(QHYZgf|8RqcgX!!qlmN==M0c%DbOTxD)<31iZG zzGZ+zAA&+*@hD4k0l6E$hxg1Ek)8ie@os}T{!mn#m06Awh~YlsZ^QmY*tkUfY6Z`| zpPAQxg7DP)xKS-o+Pp>(_#JR+&@%*qkLOi5c5E5PaeFX#_cNY7d-jeNkU{69r?co! zKKUfgX0ruB-uT8hvbMH{@B1BVVvM0yt5K_Y%*`!z@y;N6M|(tO=2uvr56SQTPa02s z9@+kV3MU2Uu5(a0j=Iay_Ss+`@k_9O4SW4Mwd*0_(vL9n#!up{yq)#!Ci^=ZShZu( z+xMF^n^le-Tj_yV-8?^X%k4oEW2&|#rK {)ocrcQFgaD9U9FG<@otyLk32=FBfJ^M=34Ua-vdE7xgMH*lP&8%D(JGBg}* ztqx2M9)>7Z+A4%$$l~H6ci(+C&pr1XuImzpA?MGZXK5+I?ERFewMx5{?kIX26s5Yi zMXi!$Vfj&(-uWmz_jStu@7HlJ{{h9L7clb$2rM`bTB%dr+{d5!Gi2ZNF|zmn3>&-3 z=J^*1n% FFp9b^QT*@`;>RKsfRNZ&;2CDSN{af zhN1Mm|3i4>QRaU9SI9l`30~ZFx%B+=)T=cd$7wa78%3P709hM3ZS(W9EvIc5#9Cfn zzN3YrR4NUG%LyHGxf~+G#>Pf#T`QFetE;OW4twIHd!A1=n`_Z|GI|TD0hLmTs^>Cu z?~gI};7{R)Id;DPJ)Bqnbrv4`JofZ^xO8=wYZosP1OblgOqjch1Sbdr!q8`7p%_`S zJ{GY Mp&?3fR`RH+0ma=54m(k*JcIr8 vgq%dB6$Mi}^UGr8fgc^JJtuZizh zId$q-+=OuW{kntt9u31~ OeVuU_uRwI&Q5EC)YYq3SzBA<*s)`TVc06s>9iVh zV0y=!cG=lnr@Z4ZH$P9g{5<>RYKLG9qW5r`YfI^-q2Q=K&F(P2 |OeTZx z`&_?%oz>OVt}w4g4X0%gvrbO$APCu5-^5yt6V3;vce}J(JGNeocew|1!bj=^z_#Mf z<2r7GH9+)P$C$Xh+1{FSNRmCjhqV3Zs3JsF<-rFZ 77EyW8kjOMtzxXhN;_yYSw~UduY46 zkK0kPqx8aY2GBccqbs+7-kp)B2omW{K4(nx(2m`Mp=VF}pv>_&J)=59yuCQ_AUv2J z6KN7n O{KRP+lDs}`Enhd^KYg z{muppingr#u$ 7xD>Ej6wMsH2IG*)dp@-#GxH5m^@+4}K< zPO3V7^XgH!w0F0eLB#1Xf12*Nj`VqNz+<;Mj3l8%8E#fb12&SqE6HJyhsEz0*12X9 z2R Q*EW)6 _2 zMQ5r7Vwi7nv*V3%sMo7(ZIxPwZg$p7MT*FXX&pT&9STnnaa!Hs5s4~v75p$H@B@55 zY$Xd5+I5EfwWr6hYQiH)7&>fOyJN=|$B$x-!l%QcT>Y@B<2bmkaOKK{c!Nz+l5Apg zY2$@$mk(HL<6}@9jEM!R6;h8DEUEVo!}gEFXBtL$HH^z0`t5v6?IIJwiML{k2)SI2 zSH0@q4*WdLy?Mv+J^Iml(2-@COorLn8Or4nLC~H1YOj0TJ2RqH7`A%!MzocP=~d%C z&2fjsRvx5ZiHXMbc |0_t^WlG_CucLpan28P15~$BTzqp+Px~$=|z`%t4RU7`y|LLtC#kjA;*&FMBzx zW549!pv!bSHwST4he>?;b`IqChB&0!wz4x3=o17*6+ZNIt3jh?(*=b9G3W850Mez^QFjdzDRYLmpv z$4#zH>ZH9~=bFYa@2G&xxIV`;jdv$Ghj3B{=vF#YFQ>Vt!P%ZPDLhU)+G!kb#tG+6 zb~ea(r&8U?b4`;E(wl*v48u?Rcz4u7juQ?WmM@r;8SjL-4wD6$B%d*j pF07*qoM6N<$g1V6D ANB{r; literal 8383 zcmeHthc{eN+plhj7F~!sdN0u#-HhIAv>-?jK@fe^=!{;1AR~r|-n-~EM3m7*iQXmZ zJ@5Lyd%wHx-*DHgGiRN>*FJlnv-k7-%04lAI_kuPPY5wEFo @(wJm5do zfY}T L$jPGx3h}*R z+N$_yOnPc=ZZbkAP7DlY448_dk>A3>#{iG#GeHB8tLj$MR$iBj2L5?}vy3iDEQrGg zHw}C{*B3Nl_R%hyvY$RuF2Zd!WOQIwTus~&bkfs9T6hcwN^m;7)_$?xx^4vwdd}cu zPoYXaItOzLITLFa)0>uW(~w`S& Jr#C+eGMX=d*1$B(fAUJLkS9D zr+xCr%QGag3!jL#GD`%L8n;ax$+RU{&WGsfB?}rFnL%}Q5=GZVS>h$MQ=P>$0@P#6 z`$FvYZ|G_UXz@QP&S4Re{n~CD3a$t%Nt_^>C-C@oSk!LMhAK(P%ni`5-L}mk B*JiPKiZB zQNer6d3zF3dp20!%g jMe--VJGoVoUBn0H`qn`2V3v70*N2G9RWk Jj<{y3G46TJrSf27@E3;TmHv0w{i>nN6fsz@jC?PlOd_j4^(Sc_lZ*o zNN>RW^miGW#9db>BU1Wk#ngCM?l75BVX1dSiEY*&Ot}XQ)o!_MUA;wi75U~k2Qgd= z65NEF6B9ROCTC7Y+0gP;|G-C#;dz7z{oKEQ3W~Qz@!w#`u_ySy>BZ55{%H{%7L8HJ z=Bu-#O-rL@VfW?}l`B*hJX _~~lWLVD$v $3 zGMGl~6^3S*-^3mU*L@!?x8wJA(JRh;TOV_R7I)hm cSXuIDP$iyz~BgPfT2#oCvS>sQvbI %Dna^@!Q@6ySZYX2=`EaO{fM*S+@y-;E}9X3OL>D2u+L3 zXUD315%IN{^Q+iNi7dvs5vZ54cp2g*j(Zm_Qf_khc+CScHa7PCg)rai7s_>pr8@cs z1|qxlP80bAZ;oC-!Q|&xSERY&b$qW4P;?yMW5(0$aKaT^T3WdH_#7VK*cIjy_%IXU zgcQ3rw=lhu3eRk6+Ol9AafAg_M8FQ_^6UpzT=luU!CS>ZG7Z9SxL~{hQhU2@t_^$I z(28|~wc}4Kh9)LzZ{7%6f6E*m9wsOl17dP4SEAN)Q-gBztSqa)zu#50`*Y9r#h!Vi z`x5(5OF6~Rbz&lkd)tXxPHwK0$EwxBg3`|xH%aw~Pj>Zg;g1_1`;gCA#<26M_y<(S zlSR&isNSp{s3? RsIU4 qW@+r6G5s1w-^&!ZOjhZ!}bClgR*>UFp?i+F??=RBt)) Rc2ke3(9iSZ%CjbDhiL$Zxyp=?YJsfE2C4ijDycjoCs(P zR|wrj@t`7B4X=`<#GQ}3qi@Qx*tqy$>d=Od;-Vj!Amg{j6NZu@6#O?Kup_5V^%b;& z%aRqBJ46ou;p5>3K7nt?=pws}!d%|J9UExgLC+?n)HRe3K7t$mSaOL3(TRwPv@~yO z;<2QsjO&Y<;k0_?Sj88YkwJafcBXUKvM12sI^P4w#-D3>#~V%Z6bQQ-`vDRSP0jgc zFV3sw0KsR^o;`mzV?2M~c{ iCx60 zGdXiB0VM~`D_wy67q0)f-LSYbaS708;zf}la8NnpvIVc;S?u~~KPFB0zrxM;7}(g4 zBgk;D;E#jyoPhwMNKlK;7AlyK7{w=7s v)nm#kGaX4G%Z6sro9GXf{cQ$+Qirp4e=N(i$ z$#wo`ealY#yn4%yI_Nb%7tf%}1v#sBVWN-U1Fhe-yX~C~({_s`qxw54k4x7FP>&XJ zchPG?&dAhM^v!bHJ{4i4+U?S_+2`RX)cid#?v1m5SrTuoGhE#pbEl>Z!n#+hjtaRn z#4(b=F*!L;n61Ju9$xUUr9wvoU0{f+bIDJW%u@HP9nF{OMuIKb#or#%?3p^D`uW<- z68&pdvmy_
bE7*2y5iwwH=ApqFje(eLC_B5Xyhl0NQ)q5^9s;+b?Ld*5 ze<}2 xtRboz0KHeV@d(%OtVJ zASi4ZqxwF;<=+xE&P$0kUerLUVQfCp<0FV_(`!g|?UG-cG!pYGr=qDCwUsYKGxwgl z6O!riz})cc1K-H@ph%l;YC>NeO>N-6(~6e(&wj;`7aRKhUo9I?cgw$>9`};gzMA1_ zvleXiIap6oXUwiC`7E7MGL%!PpMP$5uir!iGbw95<=C>Rj=EY7j!jy==3Xjj&`){7 zJk^NL#?3M)If&((*j22!O}9g=JcfWc_BGze)JUDhs1W=6``7B;J3C~%UJNDM)|kWr z6wcaj4fn9~Az0jPA??C9P<|!N#N1j0_la;}1I)LIA`?9^GrI!2LnJUPUwvahKhUBa z4UPHretOp-QIjk91!9_%rorL$^gdM{L)u{P$nkL w$4!1H&K)1^Y*R_Y-5?A{np z7FigOH|=QqM>!`a1=G!^yiPbx`X}w{8cA0t1nn=71ywsaWBU&m$_x*y5Q4u%v9W93 z^n)FNChmdB<++Dyp3NX1Z MC2xG4h(i`DtkhgQfH96U7YD}e> xNrPy9y^9Uig!~QPgxu9))m47rDa^g& z- tHUK%bVCBaWrLocUe}WE%Gl)r+Qrp1PXtSQu!a%cKoF_KARm|oWL^V3 zJq0j1oy2=1 fKQ9O&eqT7LJn$PpSoXAgb zG|xgxRhG&~NMt&T4O_lx@2hbf;o|52SS7{7f^$v#PCYv^fsRT{o1zgdS200HB^BbY zI{OX`8?JO38I^j;_{7*a#gWcxHhRgc&ZqxXz}B^b5&$A(N*=pExmi;{R8&-y)YLC% z@vNSfo;U{+Y79F=C{%ioC{M< tW7h#m$^K (Bco4HLuu?Sd>{bYAq#+?d+@D#MQi2+DNSRC^lw*? j#& zjIjN31Vk#p{{b%Ku{BC(VQE?R 74vu3)X0XDGcE&=pM8wE(O??OZl=8Qi`@kND5OHe!jb@Pw}R1yFUt|#qa7zH91 z_Ss Un)C@q;B zW|_=94-k16|EV6(ZViS#F|B#S3ImUb02AaO0u#v|z3dgXpMDO u_5BkNlfy6Q?Ha5TZPMRkfeSoZ} zh@Z6%NVvSb RVfnulL1qI%?0&Qc;M|3q}AkR9Hwz!PL~$=jpX~*uVx0 z1X2JH+Q%RqVEH5xYI9O-c{UGDObi_O6z^TvN#`gaz?7=po1Tu1H}3{T$F$5|HpBX_ zvNJpb+_~eG^Ie`qN`;?YgnL ING9?+V}!|E<9POOF4|Q93v}@(sqtPy9dH{695;k2(D-NIM2APsiPlN#JV9 z+pFE-^P)29mUnsc!{b6kyL)?O6%~1t{D)Ebr76v&wL!~728BjEsv_BKtA%t?if(TF z04t#I33XHZLDUNX{xlk`2^0!s@&;^Wh10EKC)5|0fnoD!ox8icW=$Sz5vW9$93Yd2 zbu)L{CbzUmCo;+ncXf4T%IA%DQ %trd~&2AQolo I+I}3aBgq8708JRgti9Y!afRiI46hg_;CceHnDKc
>>uY}$3e|Ca z9)U59WB&A`oe9xmpXOlmt$BP$yUNM~rjJOB0(0v$hc>wDP)@681O1ynfZ^*and^Cp z$yU-LXSN`Aj1e3bwY$M?2a3Us6Fn;{xlx+yo?SLrD6u##HCHiLSXFlh^Kk-Ab%M}Z zFQjXV;!87Q;Ioh<@f(@JSSB`qEV=U)@Ir{{-}cVpy5AGW)|X-@bF zoA?w1wM7}PkadEWndyalct{uN@$=6ng@T0W1^^L&%x+;};c~s9Ho8p4Z5Xcyvck8- z)m^LKN!b9i;?>wF^R}j|>}X#@0+_ft;RoW$a$brEp?FFp+0IZcGdJin C$4;^($# K#pS^a}T%i@Y$1}4o~kK&CWSoAP{ zFkNO g9wi$xyZ9$j74^@N`obC5@XiiGJ}&e75F{PJ@B!oT)H zlOj7^{C|uE)uE1+xjD&C^#&W=|KC{nA7h~xMZ`fKTU3bJt$MwqaJbZ(xjB+KJu}nS z;D$D ;(ZJk%XgHmBzCA! Py+| q|SbH zCQG6tM?!SwG0d?tAK|fiv^)ieuoFLOtnoP69-1`c6R(i}W565kXkJ%W=du0K*K^j& zx7u-p8o>CjUtcYyym!ceEdNx-N6*4yc>JSGGhi!}m6ffb$}5Kf@7vVcZlgcp=dWK= zzkc-t{9ejyi%7=za8$rGi!a2 ~r=y}1$Kx_b$Cv0ghCtHi8<9PqRBrpb9=DHfOakm4O4UyQ=(h)4 zk>oxFMfb{{e5U}X4sn~)vFT ;Fc65PIs}a#(cGgut*(E8b_Rt}I~25_(#+M?fjQ6hB>t z;4L@Pn?1}9G#_RR=v(3D$)O=(LaAlaSBqYxGcz-Q4iF58RQmKd#CPo3Y$57Z1LWf3 z;%}h*)>v*PdoDmK>*~^Mg(UZ7xMC5+7+_ct5{Vb;AR-ln6zM<_5`Q(%0262?Q4kU% zHU!smUx%n%6y-`?U+YR;p2SgZ&f|F6Gc3R3KkNKQ!6WeS=%vl29GSRM78HSni03Q! z&htw&GU(aBZY2BxuWKIWHt!lnGdld3BA$zlu3fwLauel?r&7{FVF3y+NbK1&V#C7t zQ{u?ky{C%1Jv}{-f16M`nh|!1X 15DC#%Dnl2rpPlctlXcMDMI z(LsRMf5@*Z{K&)m74%>##?< ZJ;LPDY9!P+AD3Ijf`{Wo^^ hxFqiF~Gll4A6n-1A> z0ekLcXS+MUw6}Y|zP4TOmdoBA_f}Zc6MmZ=skCbK`< fWra{4 zsv?YcE8AlJnO3Z|Hx{fHHwJ55mAV;~;C(nh=!R;5L`Z77KC&G VJ2fdb^hmI+>+Wi00;!!_bDub|ojb)dqKQ;s z!}}@zhs0;y^QQUwTBgjVCZ+f0KHdI?Nx9w?g~E-^N&IC*b$zp%`Z8vH_)V2hFA23k zb4*0# #6CD+TL_f)>b~cQS|h{xtuk;I-co zUO?j?Z)aBfPwSd_kG;HnxMoQVIWE8n#8d6_Xd!m6k>{0=ADq$lWov$pBhy0GqoPk4 zfx)sL7d4ssRpCwB30_NO(x3|965a5Yt5{nz*4Nj|-kneXheR0}eLtIkB-zm#O2cHi zb <=+ME{tY|JBwM@7u*N@kFE1owa0IkZJGT1a!jN$?C)BD}Kl+4V5eJQH6w6Pv2 zJLuh&fw^2Jlqg5HZ9?I}e0cb!aKNQ2u$?D1_Ev5Q5R3rbSoYuJ2l`TTarqN5rcb~! zIq*ehn9p_eOQB0n)6$_`(D;|Zf786#WBei`DI#8p+0kmo#t!Ccvln((3|~K1FXT7N zCzAo}If5(?z Ei9{Tf8UT*VkuWdU7kY-2GiSpAUD~ zA=nK)?hd6Q!u#>=BY-i5E*1@H@0~BN