Context menu is one type of menu that can be implemented in android applications to show list of actions to users. Other types of menus which can be provided in android apps are options menu and popup menu. Context menus are used to display actions which are related to a specific UI element. Context menus allow users to perform certain actions on selected view.
Context menu can be provided in two ways, as fixed top bar and as floating list of menu items.
To display floating context menu, you need to call activity’s registerForContextMenu method. This method registers the view passed to it for context menu. In activity’s onCreateContextMenu, you can create menu object by inflating menu xml defined for context menu.
Method onContextItemSelected gets called when user clicks context menu items. So, you need to override this method to handle context menu click events and provide appropriate behavior.
package com.zoftino.menus;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
public class StoresActivity extends OptionsMenuActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_stores);
ListView lv = (ListView)findViewById(R.id.stores);
lv.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, StoresData.arrayOfStores));
registerForContextMenu(lv);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.context_menu, menu);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
Toast toast = null;
switch (item.getItemId()) {
case R.id.coupons:
toast = Toast.makeText(this, "Coupons context item clicked", Toast.LENGTH_LONG);
toast.show();
return true;
case R.id.cashback:
toast = Toast.makeText(this, "Cashback context item clicked", Toast.LENGTH_LONG);
toast.show();
return true;
case R.id.deals:
toast = Toast.makeText(this, "Deals context item clicked", Toast.LENGTH_LONG);
toast.show();
return true;
default:
return super.onContextItemSelected(item);
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
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="com.zoftino.menus.StoresActivity">
<ListView android:id= "@+id/stores"
android:layout_width="match_parent"
android:layout_height="match_parent"></ListView>
</RelativeLayout>
<?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/coupons"
android:title="Coupons"
app:showAsAction="never"></item>
<item android:id="@+id/cashback"
android:title="Cashback"
app:showAsAction="never"></item>
<item android:id="@+id/deals"
android:title="Deals"
app:showAsAction="never"></item>
</menu>
Using ActionMode implementation provided by android system, you can create context menus. Context menu displayed using ActionMode is called contextual action mode. Contextual action mode is displayed as bar at top of the screen on pressing contextual mode enabled view for long time. To provide contextual action mode in your app, you need to implement ActionMode call back methods and start action mode.
Contextual action mode can be enabled for single view item or multiple view items.
Contextual action mode for single item can be provided by implementing call back methods of ActionMode and starting action mode. First, you need to provide on long click listener for the view you want to display contextual action mode on pressing it for long time. In the long click event handler for the view, you need to start action mode by calling activity’s startActionMode call back method.
StartActionMode method expects ActionMode object as argument. So you need to implement ActionMode and provide instance of it to startActionMode method.
ActionMode call back methods that need to be implemented are onCreateActionMode, onPrepareActionMode and onActionItemClicked. In onCreateActionMode, you can create menu by inflating menu defined in xml. You can handle menu action clicks in onActionItemClicked call back method and take appropriate action based on the menu action clicked.
In below coupons app example on coupons screen, on long pressing store name, contextual action bar is displayed at top of the screen. Below are the screen shot and code.
package com.zoftino.menus;
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.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class CouponsActivity extends OptionsMenuActivity {
private boolean isActionMode =false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_coupons);
ListView lv = (ListView)findViewById(R.id.coupons);
lv.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, StoresData.arrayOfCoupons));
TextView tv = (TextView) findViewById(R.id.storeNme);
tv.setText((String)getIntent().getStringExtra("store"));
tv.setOnLongClickListener(new View.OnLongClickListener() {
public boolean onLongClick(View view) {
if(isActionMode){
return false;
}
CouponsActivity.this.startActionMode(mActionModeCallback);
isActionMode = true;
view.setSelected(true);
return true;
}
});
}
private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.store_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.topCashback:
Toast.makeText(CouponsActivity.this,"View top cashback offers clicked for the selected store", Toast.LENGTH_LONG).show();
mode.finish();
return true;
case R.id.vDeals:
Toast.makeText(CouponsActivity.this,"View deals clicked", Toast.LENGTH_LONG).show();
mode.finish();
return true;
case R.id.topCoupons:
Toast.makeText(CouponsActivity.this,"View top coupons clicked", Toast.LENGTH_LONG).show();
mode.finish();
return true;
default:
return false;
}
}
@Override
public void onDestroyActionMode(ActionMode mode) {
isActionMode = false;
}
};
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_coupons"
android:orientation="vertical"
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="com.zoftino.menus.CouponsActivity">
<TextView
android:text=""
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/storeNme"
android:paddingTop="40dp"
android:textSize="20dp"
android:textColor="@color/colorAccent"
android:paddingBottom="40dp"></TextView>
<ListView android:id= "@+id/coupons"
android:layout_width="match_parent"
android:layout_height="match_parent"></ListView>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/vDeals"
android:title="View Deals"></item>
<item android:id="@+id/topCoupons"
android:title="View Top Coupons"></item>
<item android:id="@+id/topCashback"
android:title="View Cashback Offers"></item>
</menu>
By providing contextual action mode for multiple items, you can allow users to perform actions on selected multiple items. For example, you can enable contextual action mode for list view. On selecting multiple list items, contextual action bar can be displayed allowing user to perform some actions on the selected items.
To implement contextual action mode for list view, you need to set choice mode of the list view to CHOICE_MODE_MULTIPLE_MODAL by calling setChoiceMode on the list view and you need to set listener for the list view by calling setMultiChoiceModeListener method of list view passing MultiChoiceModeListener object. MultiChoiceModeListener has several methods that need to be implemented to create action mode and handle action item click events.
package com.zoftino.menus;
import android.os.Bundle;
import android.util.SparseBooleanArray;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.AbsListView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
public class ShopsActivity extends OptionsMenuActivity implements AbsListView.MultiChoiceModeListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_stores);
ListView lv = (ListView) findViewById(R.id.stores);
lv.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, StoresData.arrayOfStores));
lv.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
lv.setMultiChoiceModeListener(this);
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
ListView lv = (ListView) findViewById(R.id.stores);
switch (item.getItemId()) {
case R.id.topCashback:
Toast.makeText(this, getSelectedItems(lv)+" selected", Toast.LENGTH_LONG).show();
mode.finish();
return true;
case R.id.vDeals:
Toast.makeText(this, getSelectedItems(lv)+" selected", Toast.LENGTH_LONG).show();
mode.finish();
return true;
case R.id.topCoupons:
Toast.makeText(this,"View top coupons clicked", Toast.LENGTH_LONG).show();
mode.finish();
return true;
default:
return false;
}
}
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.store_menu, menu);
return true;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
}
@Override
public void onItemCheckedStateChanged(ActionMode mode, int position,
long id, boolean checked) {
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
public static String getSelectedItems(ListView listView) {
String selectedIds = "";
SparseBooleanArray selectedItems= listView.getCheckedItemPositions();
for (int i = 0; i < selectedItems.size(); i++) {
if (selectedItems.valueAt(i)) {
selectedIds = listView.getAdapter().getItem(selectedItems.keyAt(i)).toString();
}
}
return selectedIds;
}
}