DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

How does AI transform chaos engineering from an experiment into a critical capability? Learn how to effectively operationalize the chaos.

Data quality isn't just a technical issue: It impacts an organization's compliance, operational efficiency, and customer satisfaction.

Are you a front-end or full-stack developer frustrated by front-end distractions? Learn to move forward with tooling and clear boundaries.

Developer Experience: Demand to support engineering teams has risen, and there is a shift from traditional DevOps to workflow improvements.

Related

  • Issue and Present Verifiable Credentials With Spring Boot and Android
  • How to Build a React Native Chat App for Android
  • Using Jetpack Compose With MVI Architecture
  • Implementing SOLID Principles in Android Development

Trending

  • Securing DevOps Pipelines: A Practical Guide to Balancing Speed and Security
  • Enterprise Data Loss Prevention (DLP) Security Policies and Tuning
  • How to Introduce a New API Quickly Using Micronaut
  • Mastering Advanced Traffic Management in Multi-Cloud Kubernetes: Scaling With Multiple Istio Ingress Gateways
  1. DZone
  2. Testing, Deployment, and Maintenance
  3. Deployment
  4. Contextual Action Bar (CAB) in Android

Contextual Action Bar (CAB) in Android

By 
Paresh  Mayani user avatar
Paresh Mayani
·
Oct. 24, 13 · Tutorial
Likes (0)
Comment
Save
Tweet
Share
56.4K Views

Join the DZone community and get the full member experience.

Join For Free

Before getting into the action bar and Contextual Action bar concept and the coding for it, let me take you through the concept of two ways to show contextual actions:

1. Floating Context Menu
2. Contextual Action Mode

1. Floating Context Menu

android context menu

In earlier versions of Android, we were used to seeing almost all the apps having context menus ready for showing options (menu items) whenever the user performs a long press on any element. We can say long press gesture was universally used to display contextual actions in a context menu.

“Long press gesture – That is, a touch that’s held in the same position for a moment.”

Now, since Android 3.0, the purpose of Long press gesture has changed. It's now used to handle multi-select and contextual actions.

2. Contextual Action Mode

  • The contextual action mode is a system implementation of ActionMode that 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).

ActionMode

Represents a contextual mode of the user interface. Action modes can be used to provide alternative interaction modes and replace parts of the normal UI until finished. Examples of good action modes include text selection and contextual actions.

Contextual Action Bar (CAB)

A Contextual action bar (CAB) is a temporary action bar that overlays the app’s action bar for the duration of a particular sub-task.


android contextual action bar

As I have mentioned earlier, CABs are used for tasks that involve acting on selected data or text. For example: Cut, Copy, Paste, Delete, or any other operations can be performed on single or batches of selected data.

Android contextual action bar

As shown in snap-1 (left) above, the Contextual Action bar (Selection CAB) appears at the top bar as soon as the user performs the long press gesture. From here the user can:

  1. Select more items or deselect items by just touching them
  2. Select and trigger any actions displayed in the bar; the selected action triggers all the selected items. Then the action bar automatically dismiss itself.
  3. You can dismiss CAB in 3 ways:
    • Deselect all the selected items
    • Press the Back key from navigation bar
    • Select the Check mark button (left) from the CAB. It doesn’t dismiss only the CAB, but also removes the selection on data which you have done.

When to Use Which? (Context Menu or CAB)

Now, I am sure there is no doubt regarding when to use Context Menu and when to CAB. As I have mentioned, if you are developing an app for android 3.0 or higher, you should use Contextual Action bar instead of displaying menu items in floating context menu.

And if you are providing compatibility to a lower Android version, you should fall back to a floating context menu on those devices.

Using Contextual Action Bar (CAB):

There are 2 designs by which you can implement Contextual Action bar:

  1. Enable CAB when the user selects a particular view
  2. Enable CAB whenever the user performs a long press gesture on particular view

1: Enable CAB When User Selects a Particular View

If you want to invoke the contextual action mode only when the user selects particular views, then follow the below steps:

  1. Implement the ActionMode.Callback interface. 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).

Implement the ActionMode.Callback interface:

class ActionBarCallBack implements ActionMode.Callback {

        @Override
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            // TODO Auto-generated method stub
            return false;
        }

        @Override
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            // TODO Auto-generated method stub
            mode.getMenuInflater().inflate(R.menu.contextual_menu, menu);
            return true;
        }

        @Override
        public void onDestroyActionMode(ActionMode mode) {
            // TODO Auto-generated method stub

        }

        @Override
        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            // TODO Auto-generated method stub

            mode.setTitle("CheckBox is Checked");
            return false;
        }

    } 

Call startActionMode()

MainActivity.this.startActionMode(new ActionBarCallBack());

For example:
Let’s build an example to enable Contextual action mode on the CheckBox selection.

package com.technotalkative.contextualactionbarsingle;

import android.app.Activity;
import android.os.Bundle;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;

public class MainActivity extends Activity {

    private ActionMode mActionMode;
    private CheckBox checkBox1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        getActionBar().setTitle("CAB demo - Individual view");
        checkBox1 = (CheckBox) findViewById(R.id.checkBox1);
        checkBox1.setOnCheckedChangeListener(new OnCheckedChangeListener() {

            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                // TODO Auto-generated method stub

                if(isChecked)
                    mActionMode = MainActivity.this.startActionMode(new ActionBarCallBack());
                else
                    mActionMode.finish();
            }
        });
    }

    class ActionBarCallBack implements ActionMode.Callback {

        @Override
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            // TODO Auto-generated method stub
            return false;
        }

        @Override
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            // TODO Auto-generated method stub
            mode.getMenuInflater().inflate(R.menu.contextual_menu, menu);
            return true;
        }

        @Override
        public void onDestroyActionMode(ActionMode mode) {
            // TODO Auto-generated method stub

        }

        @Override
        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            // TODO Auto-generated method stub

            mode.setTitle("CheckBox is Checked");
            return false;
        }

    }
}

2: Enable CAB When User Performs a Long Press Gesture on Particular View

If you want to invoke the contextual action mode only when the user performs a long press gesture on a view like ListView or GridView, and want to perform batch actions on multiple selected items, then you can implement this by following the below steps:

  1. Implement the AbsListView.MultiChoiceModeListener and set it to your ViewGroup (e.g. ListView). In its callback methods, you can specify the actions for the contextual action bar, respond to click events on action items, and handle its callback events (Which are actually inherited from ActionMode.Callback interface).
  2. Call setChoiceMode() with the CHOICE_MODE_MULTIPLE_MODAL argument.

AbsListView.MultiChoiceModeListener:

A MultiChoiceModeListener receives events for CHOICE_MODE_MULTIPLE_MODAL. It acts as the ActionMode.Callback for the selection mode and also receives onItemCheckedStateChanged(ActionMode, int, long, boolean) events when the user selects and deselects list items.

Implement the AbsListView.MultiChoiceModeListener:

getListView().setMultiChoiceModeListener(new MultiChoiceModeListener() {

            @Override
            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
                // TODO Auto-generated method stub
                return false;
            }

            @Override
            public void onDestroyActionMode(ActionMode mode) {
                // TODO Auto-generated method stub
            }

            @Override
            public boolean onCreateActionMode(ActionMode mode, Menu menu) {
                // TODO Auto-generated method stub

                MenuInflater inflater = getMenuInflater();
                inflater.inflate(R.menu.contextual_menu, menu);
                return true;
            }

            @Override
            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
                // TODO Auto-generated method stub
                return false;
            }

            @Override
            public void onItemCheckedStateChanged(ActionMode mode, int position,
                    long id, boolean checked) {
                // TODO Auto-generated method stub
            }
        });

Call setChoiceMode() with the CHOICE_MODE_MULTIPLE_MODAL argument:

getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);

Full example:
Have you used Gmail Android app? (stupid question :) ), but if you have used it, then I am sure you have tried to perform long gesture on mails to delete messages, so let’s develop a similar example. Here we will enable contextual action mode whenever the user performs long press gestures, and we will display number of items selected.

Step 1: Take ListView in activity_main.xml layout

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity"
    android:background="@android:color/background_light" >

    <ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:choiceMode="multipleChoice">
    </ListView>

</RelativeLayout>

Step 2: Define row layout (row_list_item.xml) for ListView

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:layout_gravity="center_vertical"
    android:padding="5dp"
    android:background="@android:color/background_light" >

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_launcher" />

    <TextView
        android:id="@+id/textView1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="17sp"
        android:layout_marginLeft="10dp"
        android:text="Test"
        android:textStyle="bold" />

</LinearLayout>

Step 3: Create a contextual menu (contextual_menu.xml) in menu folder, this menu gets displayed as contextual action bar whenever user performs long press gesture

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:id="@+id/item_delete"
        android:icon="@android:drawable/ic_menu_delete"
        android:showAsAction="ifRoom|withText"
        android:title="Delete"
        android:titleCondensed="Delete">
    </item>

</menu>

Step 4: Implement MultiChoiceModeListener and call setChoiceMode() inside MainActivity

  • Inside onCreateActionMode() – We will enable contextual action mode with menu we have defined.
  • Inside onActionItemClicked() – We can perform contextual actions on the selected items.
  • Inside onItemCheckedStateChanged() – we can decide which items are selected and which are not. Here we will prepare title for the action bar with particular no. of items are selected.
package com.technotalkative.contextualactionmultiple;

import java.util.HashMap;
import java.util.Set;

import android.app.ListActivity;
import android.content.Context;
import android.os.Bundle;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView.MultiChoiceModeListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class MainActivity extends ListActivity {

    private String[] data = {"One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine","Ten"};

    private SelectionAdapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mAdapter = new SelectionAdapter(this,
                    R.layout.row_list_item, R.id.textView1, data);
        setListAdapter(mAdapter);
        getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);

        getListView().setMultiChoiceModeListener(new MultiChoiceModeListener() {

            private int nr = 0;

            @Override
            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
                // TODO Auto-generated method stub
                return false;
            }

            @Override
            public void onDestroyActionMode(ActionMode mode) {
                // TODO Auto-generated method stub
                 mAdapter.clearSelection();
            }

            @Override
            public boolean onCreateActionMode(ActionMode mode, Menu menu) {
                // TODO Auto-generated method stub

                nr = 0;
                MenuInflater inflater = getMenuInflater();
                inflater.inflate(R.menu.contextual_menu, menu);
                return true;
            }

            @Override
            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
                // TODO Auto-generated method stub
                switch (item.getItemId()) {

                    case R.id.item_delete:
                        nr = 0;
                        mAdapter.clearSelection();
                        mode.finish();
                }
            }

            @Override
            public void onItemCheckedStateChanged(ActionMode mode, int position,
                    long id, boolean checked) {
                // TODO Auto-generated method stub
                 if (checked) {
                        nr++;
                        mAdapter.setNewSelection(position, checked);                   
                    } else {
                        nr--;
                        mAdapter.removeSelection(position);                
                    }
                    mode.setTitle(nr + " selected");

            }
        });

        getListView().setOnItemLongClickListener(new OnItemLongClickListener() {

            @Override
            public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
                    int position, long arg3) {
                // TODO Auto-generated method stub

                getListView().setItemChecked(position, !mAdapter.isPositionChecked(position));
                return false;
            }
        });
    }

    private class SelectionAdapter extends ArrayAdapter<String> {

        private HashMap<Integer, Boolean> mSelection = new HashMap<Integer, Boolean>();

        public SelectionAdapter(Context context, int resource,
                int textViewResourceId, String[] objects) {
            super(context, resource, textViewResourceId, objects);
        }

        public void setNewSelection(int position, boolean value) {
            mSelection.put(position, value);
            notifyDataSetChanged();
        }

        public boolean isPositionChecked(int position) {
            Boolean result = mSelection.get(position);
            return result == null ? false : result;
        }

        public Set<Integer> getCurrentCheckedPosition() {
            return mSelection.keySet();
        }

        public void removeSelection(int position) {
            mSelection.remove(position);
            notifyDataSetChanged();
        }

        public void clearSelection() {
            mSelection = new HashMap<Integer, Boolean>();
            notifyDataSetChanged();
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View v = super.getView(position, convertView, parent);//let the adapter handle setting up the row views
            v.setBackgroundColor(getResources().getColor(android.R.color.background_light)); //default color

            if (mSelection.get(position) != null) {
                v.setBackgroundColor(getResources().getColor(android.R.color.holo_blue_light));// this is a selected position so make it red
            }
            return v;
        }
    }
}

Download Example:

https://github.com/PareshMayani/Contextual-Action-Bar



Android (robot)

Published at DZone with permission of Paresh Mayani. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Issue and Present Verifiable Credentials With Spring Boot and Android
  • How to Build a React Native Chat App for Android
  • Using Jetpack Compose With MVI Architecture
  • Implementing SOLID Principles in Android Development

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • [email protected]

Let's be friends: