Android Application Development Cookbook(Second Edition)
上QQ阅读APP看书,第一时间看更新

Enabling Contextual Action Mode for a view

A Context Menu provides additional options related to a specific view—the same concept as a right-click on the desktop. Android currently supports two different approaches: the floating Context Menu and Contextual Mode. Contextual Action Mode was introduced in Android 3.0. The older floating Context Menu could lead to confusion since there was no indication of the currently selected item and it didn't support actions on multiple items—such as selecting multiple emails to delete in one action.

Creating a Floating Context Menu

If you need to use the old style Context Menu, for example, to support preAndroid 3.0 devices, it's very similar to the Option Menu API, just different method names. To create the menu, use onCreateContextMenu() instead of onCreateOptionsMenu(). To handle the menu item selection, use onContextItemSelected() instead of onOptionsItemSelected(). Finally, call registerForContextMenu() to let the system know you want Context Menu events for the view.

Since Contextual Mode is considered the preferred way to display context options, this recipe will focus on the newer API. Contextual Mode offers the same features as the floating Context Menu, but also adds additional functionality by allowing multiple item selection when using batch mode.

This recipe will demonstrate the setup of Contextual Mode for a single view. Once activated, with a long press, a Contextual Action Bar (CAB) will replace the Action Bar until Contextual Mode is finished.

Note

The Contextual Action Bar is not the same as the Action Bar and your activity does not need to include an Action Bar.

Getting ready

Use Android Studio to create a new project and call it ContextualMode. Use the default Phone & Tablet option and select Empty Activity when prompted to add an Activity. Create a menu directory (res/menu) as we did in the first recipe, Creating an Options menu, to store the XML for the contextual menu.

How to do it...

We will create an ImageView to serve as the host view to initialize Contextual Mode. Since Contextual Mode is usually triggered with a long press, we will set up a long click listener in onCreate() for the ImageView. When called, we will start Contextual Mode and pass an ActionMode callback to handle the Contextual Mode events. Here are the steps:

  1. We will start by adding two new string resources. Open the strings.xml file and add the following:
    <string name="menu_cast">Cast</string>
    <string name="menu_print">Print</string>
  2. With the strings created, we can now create the menu by creating a new file in res/menu called context_menu.xml using the following XML:
    <?xml version="1.0" encoding="utf-8"?>
    <menu
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
    <item android:id="@+id/menu_cast"
        android:title="@string/menu_cast" />
    <item android:id="@+id/menu_print"
        android:title="@string/menu_print" /> </menu>
  3. Now add an ImageView to activity_main.xml to serve as the source for initiating Contextual Mode. Here is the XML for the ImageView:
    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        android:src="@mipmap/ic_launcher"/>
  4. With the UI now set up, we can add the code for Contextual Mode. First, we need a global variable to store the ActionMode instance returned when we call startActionMode(). Add the following line of code to MainActivity.java below the class constructor:
    ActionMode mActionMode;
  5. Next, create an ActionMode callback to pass to startActionMode(). Add the following code to the MainActivity class below the code in the previous step:
    private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
        @Override
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            mode.getMenuInflater().inflate(R.menu.context_menu, menu);
            return true;
        }
        @Override
        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            return false;
        }
        @Override
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            switch (item.getItemId()) {
                case R.id. menu_cast:
                    Toast.makeText(MainActivity.this, "Cast", Toast.LENGTH_SHORT).show();
                    mode.finish();
                    return true;
                case R.id. menu_print:
                    Toast.makeText(MainActivity.this, "Print", Toast.LENGTH_SHORT).show();
                    mode.finish();
                    return true;
                default:
                    return false;
            }
        }
        @Override
        public void onDestroyActionMode(ActionMode mode) {
            mActionMode = null;
        }
    };
  6. With the ActionMode callback created, we just need to call startActionMode() to begin Contextual Mode. Add the following code to the onCreate() method to set up the long click listener:
    ImageView imageView = (ImageView)findViewById(R.id.imageView);
    imageView.setOnLongClickListener(new View.OnLongClickListener() {
        public boolean onLongClick(View view) {
            if (mActionMode != null) return false;
            mActionMode = startActionMode(mActionModeCallback);
            return true;
        }
    });
  7. Run the program on a device or emulator to see the CAB in action.

How it works...

As you saw in Step 2, we have used the same menu XML to define the contextual menu as the other menus.

The main piece of code to understand is the ActionMode callback. This is where we handle the Contextual Mode events: initializing the menu, handling menu item selections, and cleaning up. We start Contextual Mode in the long press event with a call to startActionMode() by passing in the ActionMode callback created in Step 5.

When action mode is triggered, the system calls the onCreateActionMode() callback, which inflates the menu and displays it in the Contextual Action Bar. The user can dismiss the Contextual Action Bar by pressing the back arrow or the back key. The CAB is also dismissed when the user makes a menu selection. We show a Toast to give a visual feedback for this recipe but this is where you would implement your functionality.

There's more...

In this example, we store the ActionMode returned from the startActionMode() call. We use it to prevent a new instance from being created when the Action Mode is already active. We could also use this instance to make changes to the Contextual Action Bar itself, such as changing the title with the following:

mActionMode.setTitle("New Title");

This is particularly useful when working with multiple item selections as we'll see in the next recipe.

See also

  • See the next recipe, Using Contextual Batch Mode with a ListView, to work with multiple items selection