Learning Resources
 

Using context menus in Android


Context menu and contextual action mode
A context menu is a floating menu that appears when the user performs a long-click on an element. It provides actions that affect the selected content or context frame.

When developing for Android 3.0 and higher, you should instead use the contextual action mode to enable actions on selected content. This mode displays action items that affect the selected content in a bar at the top of the screen and allows the user to select multiple items.

 

Creating Contextual Menus


Figure 3. Screenshots of a floating context menu (left) and the contextual action bar (right).

A contextual menu offers actions that affect a specific item or context frame in the UI. You can provide a context menu for any view, but they are most often used for items in a ListView, GridView, or other view collections in which the user can perform direct actions on each item.

There are two ways to provide contextual actions:

  • In a floating context menu. A menu appears as a floating list of menu items (similar to a dialog) when the user performs a long-click (press and hold) on a view that declares support for a context menu. Users can perform a contextual action on one item at a time.
  • In the contextual action mode. This mode is a system implementation of ActionModethat displays a contextual action bar at the top of the screen with action items that affect the selected item(s). When this mode is active, users can perform an action on multiple items at once (if your app allows it).

Note: The contextual action mode is available on Android 3.0 (API level 11) and higher and is the preferred technique for displaying contextual actions when available. If your app supports versions lower than 3.0 then you should fall back to a floating context menu on those devices.

Creating a floating context menu

To provide a floating context menu:

  1. Register the Viewto which the context menu should be associated by calling registerForContextMenu()and pass it the View.

    If your activity uses a ListViewor GridViewand you want each item to provide the same context menu, register all items for a context menu by passing the ListViewor GridViewto registerForContextMenu().

  2. Implement the onCreateContextMenu()method in your Activityor Fragment.

    When the registered view receives a long-click event, the system calls your onCreateContextMenu()method. This is where you define the menu items, usually by inflating a menu resource. For example:

    @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);
    }

    MenuInflaterallows you to inflate the context menu from a menu resource. The callback method parameters include the Viewthat the user selected and a ContextMenu.ContextMenuInfoobject that provides additional information about the item selected. If your activity has several views that each provide a different context menu, you might use these parameters to determine which context menu to inflate.

  3. Implement onContextItemSelected().

    When the user selects a menu item, the system calls this method so you can perform the appropriate action. For example:

    @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;
            default:
                return super.onContextItemSelected(item);
        }
    }

    The getItemId()method queries the ID for the selected menu item, which you should assign to each menu item in XML using the android:idattribute, as shown in the section about Defining a Menu in XML.

    When you successfully handle a menu item, return true. If you don't handle the menu item, you should pass the menu item to the superclass implementation. If your activity includes fragments, the activity receives this callback first. By calling the superclass when unhandled, the system passes the event to the respective callback method in each fragment, one at a time (in the order each fragment was added) until trueor falseis returned. (The default implementation for Activityand android.app.Fragmentreturn false, so you should always call the superclass when unhandled.)

Using the contextual action mode

The contextual action mode is a system implementation of ActionModethat focuses user interaction toward performing contextual actions. When a user enables this mode by selecting an item, a contextual action bar appears at the top of the screen to present actions the user can perform on the currently selected item(s). While this mode is enabled, the user can select multiple items (if you allow it), deselect items, and continue to navigate within the activity (as much as you're willing to allow). The action mode is disabled and the contextual action bar disappears when the user deselects all items, presses the BACK button, or selects the Done action on the left side of the bar.

Note: The contextual action bar is not necessarily associated with the action bar. They operate independently, even though the contextual action bar visually overtakes the action bar position.

If you're developing for Android 3.0 (API level 11) or higher, you should usually use the contextual action mode to present contextual actions, instead of the floating context menu.

For views that provide contextual actions, you should usually invoke the contextual action mode upon one of two events (or both):

  • The user performs a long-click on the view.
  • The user selects a checkbox or similar UI component within the view.

How your application invokes the contextual action mode and defines the behavior for each action depends on your design. There are basically two designs:

  • For contextual actions on individual, arbitrary views.
  • For batch contextual actions on groups of items in a ListViewor GridView(allowing the user to select multiple items and perform an action on them all).

The following sections describe the setup required for each scenario.

Enabling the contextual action mode for individual views

If you want to invoke the contextual action mode only when the user selects specific views, you should:

  1. Implement the ActionMode.Callbackinterface. In its callback methods, you can specify the actions for the contextual action bar, respond to click events on action items, and handle other lifecycle events for the action mode.
  2. Call startActionMode()when you want to show the bar (such as when the user long-clicks the view).

For example:

  1. Implement the ActionMode.Callbackinterface:
    private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
    
        // Called when the action mode is created; startActionMode() was called
        @Override
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            // Inflate a menu resource providing context menu items
            MenuInflater inflater = mode.getMenuInflater();
            inflater.inflate(R.menu.context_menu, menu);
            return true;
        }
    
        // Called each time the action mode is shown. Always called after onCreateActionMode, but
        // may be called multiple times if the mode is invalidated.
        @Override
        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            return false; // Return false if nothing is done
        }
    
        // Called when the user selects a contextual menu item
        @Override
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            switch (item.getItemId()) {
                case R.id.menu_share:
                    shareCurrentItem();
                    mode.finish(); // Action picked, so close the CAB
                    return true;
                default:
                    return false;
            }
        }
    
        // Called when the user exits the action mode
        @Override
        public void onDestroyActionMode(ActionMode mode) {
            mActionMode = null;
        }
    };

    Notice that these event callbacks are almost exactly the same as the callbacks for the options menu, except each of these also pass the ActionModeobject associated with the event. You can use ActionModeAPIs to make various changes to the CAB, such as revise the title and subtitle with setTitle()and setSubtitle()(useful to indicate how many items are selected).

    Also notice that the above sample sets the mActionModevariable null when the action mode is destroyed. In the next step, you'll see how it's initialized and how saving the member variable in your activity or fragment can be useful.

  2. Call startActionMode()to enable the contextual action mode when appropriate, such as in response to a long-click on a View:
    someView.setOnLongClickListener(new View.OnLongClickListener() {
        // Called when the user long-clicks on someView
        public boolean onLongClick(View view) {
            if (mActionMode != null) {
                return false;
            }
    
            // Start the CAB using the ActionMode.Callback defined above
            mActionMode = getActivity().startActionMode(mActionModeCallback);
            view.setSelected(true);
            return true;
        }
    });

    When you call startActionMode(), the system returns the ActionModecreated. By saving this in a member variable, you can make changes to the contextual action bar in response to other events. In the above sample, the ActionModeis used to ensure that the ActionModeinstance is not recreated if it's already active, by checking whether the member is null before starting the action mode.

Enabling batch contextual actions in a ListView or GridView

If you have a collection of items in a ListViewor GridView(or another extension of AbsListView) and want to allow users to perform batch actions, you should:

For example:

ListView listView = getListView();
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
listView.setMultiChoiceModeListener(new MultiChoiceModeListener() {

    @Override
    public void onItemCheckedStateChanged(ActionMode mode, int position,
                                          long id, boolean checked) {
        // Here you can do something when items are selected/de-selected,
        // such as update the title in the CAB
    }

    @Override
    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
        // Respond to clicks on the actions in the CAB
        switch (item.getItemId()) {
            case R.id.menu_delete:
                deleteSelectedItems();
                mode.finish(); // Action picked, so close the CAB
                return true;
            default:
                return false;
        }
    }

    @Override
    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
        // Inflate the menu for the CAB
        MenuInflater inflater = mode.getMenuInflater();
        inflater.inflate(R.menu.context, menu);
        return true;
    }

    @Override
    public void onDestroyActionMode(ActionMode mode) {
        // Here you can make any necessary updates to the activity when
        // the CAB is removed. By default, selected items are deselected/unchecked.
    }

    @Override
    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
        // Here you can perform updates to the CAB due to
        // an invalidate() request
        return false;
    }
});

That's it. Now when the user selects an item with a long-click, the system calls the onCreateActionMode()method and displays the contextual action bar with the specified actions. While the contextual action bar is visible, users can select additional items.

In some cases in which the contextual actions provide common action items, you might want to add a checkbox or a similar UI element that allows users to select items, because they might not discover the long-click behavior. When a user selects the checkbox, you can invoke the contextual action mode by setting the respective list item to the checked state with setItemChecked().

 

--Google