Show a context menu for long-clicks in an Android ListView

2010-01-21
Coming from a Windows and .NET background, I had some trouble understanding how to interact with the ListView control and context menu creation in Android. Context menus are supposed to be shown on your mobile device when you touch/click the screen and hold on for a longer time. So here is how to determine which item is long-clicked and how to show a context menu for it.

Source code for this blog post is available as a complete Eclipse project at http://github.com/mikeplate/ListViewDemo (zip download link in upper right corner).

An Activity with an expanding ListView and a docked TextView

If you have an activity that will only contain a single ListView control, you can derive your activity from the ListActivity instead of Activity. However, I think I might like to show some extra info below my ListView so I chose to have a separate ListView object. My activity layout looks like this:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:orientation="vertical"
  >
  <ListView
    android:id="@+id/list"
    android:layout_width="fill_parent"
    android:layout_height="0px"
    android:layout_weight="1"
    />
  <TextView
    android:id="@+id/footer"
    android:layout_width="fill_parent"
    android:layout_height="60dip"
    android:text="@string/footer"
    android:padding="4dip"
    android:background="#FF666666"
    />
</LinearLayout>

And I need the layout for items in the ListView (listitem.xml):

<?xml version="1.0" encoding="utf-8"?>
<TextView
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:textSize="24dip"
  android:padding="8dip"
  />

Note a nice trick that I’ve used to get the TextView to “dock” at the bottom with a definied height, and have the ListView automatically fill out the rest of the height. This kind of thinking is important since Android devices can have different resolutions. The trick is to set the layout_height to zero pixels and the layout_weight to one (default is zero). Not sure about the logic behind that, but it works!

In order to have something to put into my ListView, I created a few country names in a string array as a resource and I sort that array before adding it to the ListView with the ArrayAdapter object. (Check out source code link above for this content.)

public class ListViewDemoActivity extends Activity {
  private String[] Countries;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    Countries = getResources().getStringArray(R.array.countries);
    Arrays.sort(Countries);

    ListView list = (ListView)findViewById(R.id.list);
    ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.listitem, Countries);
    list.setAdapter(adapter);
    registerForContextMenu(list);
  }
}

Creating a ContextMenu in Android

When the user long-clicks, the event onCreateContextMenu is fired for the control that the user is clicking. For me, that is the ListView control. But since I don’t want to write a custom ListView-derived class, I want to catch that event in my activity. There does not seem to be any bubbling going on. Events fired in a child control does not bubble up to the parent if they are unhandled.

But obviously, the api designers have thought of this since there is a special method for this situation. Call the registerForContextMenu in your activity for this! This will actually make sure your overridden methods for both onCreateContextMenu and onContextItemSelected is called for the ListView-events as we’ll see soon.

Next, we’ll provide the implementation of onCreateContextMenu. Here I want to ensure that the event comes from the ListView and if so, I want to determine on which item in the ListView the user long-clicked.

@Override
public void onCreateContextMenu(ContextMenu menu, View v,
    ContextMenuInfo menuInfo) {
  if (v.getId()==R.id.list) {
    AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)menuInfo;
    menu.setHeaderTitle(Countries[info.position]);
    String[] menuItems = getResources().getStringArray(R.array.menu);
    for (int i = 0; i<menuItems.length; i++) {
      menu.add(Menu.NONE, i, i, menuItems[i]);
    }
  }
}

As you can see, the argument of type ContextMenuInfo can actually change depending on what type of control is sending the event. For ListViews, the class you need to type cast into is AdapterView.AdapterContextMenuInfo. From there I used the position, which in my case corresponds to the index into the string-array. From the array I retrieve the string for that particular item and use as title for the menu. Then you can of course add all the menu commands you like. For the demo, I defined another string array as a resource with the commands I want to add.

When creating the menu items with the add-call, I specify that I don’t want any grouping of the items (Menu.NONE) and that the order and id of the item is the same (i). The last argument to add is the text to display for the item.

Screen capture of the context menu with commands

Responding to selected MenuItem

If the user dismisses the context menu (for instance, by back button) you don’t need to do anything. But for catching the actual selection of one of the items, you need to override onContextItemSelected.

@Override
public boolean onContextItemSelected(MenuItem item) {
  AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
  int menuItemIndex = item.getItemId();
  String[] menuItems = getResources().getStringArray(R.array.menu);
  String menuItemName = menuItems[menuItemIndex];
  String listItemName = Countries[info.position];

  TextView text = (TextView)findViewById(R.id.footer);
  text.setText(String.format("Selected %s for item %s", menuItemName, listItemName));
  return true;
}

The MenuItem argument holds all information that you need. The ContextMenuInfo object that got sent to onCreateContextMenu is still there and still needs type casting. Or I guess you could have saved that info in the activity between the calls, but I didn’t.

The id of the menu item selected is the same as the index into the string array of menu item texts for me. Instead of just outputting the menu command name and the list item text in a TextView, you would most likely have a big switch statement on menuItemIndex.

This was my first blog post and code demo for the Android platform. I hope it won’t be the last! The goal is to build upon this demo and/or other demos in my investigations of the Android platform. Please let me know in the comments if you have even better methods or code patterns that solves problems like this.

70 Responses to “Show a context menu for long-clicks in an Android ListView”

  1. Rickard says:

    Brilliant!

  2. sumit asok says:

    great tutorial…simple and effective.

  3. sumit asok says:

    for me this
    android:layout_height=”0px” android:layout_weight=”1″
    thing is not working
    at first it sets itself to bottom,
    but when the list increases it goes down.
    This program has an automatically increasing list.
    if any answer pls mail me.

  4. Skydancer says:

    That’s what I was searching for the whole day long. Thanks!!

  5. piyush says:

    Nice… i must say..

    Thanks ….

  6. Anonymous says:

    [...] Show a context menu for long-clicks in an Android ListView – Mike Plate [...]

  7. Thank u for providing open Source for android application

  8. hjandrzej says:

    this is absolutely fantastic!!!!! life saver! needed exactly this situation for coursework!!

    A++++

  9. BarMonger says:

    Great tutorial, thanks.
    The official API documentation is less than helpful but your guide is great :-)

  10. Hey thanks, this is *useful* code.

    … Opposed to the similar Google sample code for a ListView which is horribly assembled, missing pieces, and includes a disclaimer that you “shouldn’t ever actually do it this way”. :-)

  11. Reynold says:

    Thanks, the ListView with the docked View is exactly what I was trying to do and I made use of SetHeaderTitle as well.

  12. Weixi says:

    Thanks a bunch for the code to get which ListItem was selected! ;) Great Guide!

  13. endenis says:

    Thanks, very useful tutorial!

  14. sohaib rahman says:

    Excellent and awesome!!!!! Really a helpful stuff!

  15. Thulasi says:

    nice and very helpful tutorial..

  16. umesh says:

    its nice tutorial
    thanx

  17. Rohaan says:

    You sir, are a genius.
    Thankyouverymuch!!!
    Nice and simple. exactly what i needed.

  18. kevin says:

    hi mike,

    this was very useful, clear and to the point. thanks for posting it.

  19. Harsh says:

    Working and a very nice tutorial..!!
    appreciate the effort.

  20. Surendra says:

    public void onButtonClick(View v)
    {
    Toast.makeText(this, “Button clicked!”, Toast.LENGTH_SHORT).show();

    }
    why this Code not Work plz rply my mail

  21. Surendra says:

    Hello Sir
    My Android AVD Simulator have Some Unexped error said closed forcly why this problem occurs plz rply some solution

  22. Jason Hamm says:

    Could you please send me an explanation of the code

    if (v.getId()==R.id.list)

    I keep looking at it but it still doesn’t make sense to me.
    Thanks

    • mikeplate says:

      No problem. I’m just making sure that the View that was longpressed, is the ListView that I want to show the context menu for. I haven’t tried it, but if I were to longpress on the TextView at the bottom (with the short explanation) and didn’t have this if statement, the context menu would show for that event too. The “v” in the example is the View that was longpressed.

  23. Michael says:

    Thanks a lot! Nice, simple and useful tutorial. Keep on doin’ it.

  24. r says:

    You sir, are a savior. Thank you for the registerForContextMenu!

  25. Dave says:

    Thanks would have been days getting there …

  26. Xoce says:

    aaaaaaaaawesomE!!!

    simple but really good!

  27. timperthwa says:

    Excellent! works as advertised :)

  28. sweaty says:

    my footer text and sub menu are not shown. what should i do….
    i even copy d exect code bt still face this problem

  29. Jack Welch says:

    Thanks so much. This is crystal clear and a huge help for someone like me who decided to jump into android programming and learns best from example code.

  30. Ramya says:

    Thank you………….. it helps me alot……

  31. Maniac says:

    May God Bless Man!! You have just saved me hours end on of scouring the internet for this exact masterpiece of work….. Great work!

  32. Liviu says:

    This is perfect! Thank you!

  33. [...] by: http://www.mikeplate.com/2010/01/21/show-a-context-menu-for-long-clicks-in-an-android-listview/ Like this:LikeBe the first to like this [...]

  34. Naresh says:

    its tooo good. because its what i thought to find. i m trying this concept very long time. thankz

  35. You are quietly brilliant says:

    You are quietly brilliant!
    Thanks!!!

  36. ridwan says:

    Thanks so Much… ^_^G

  37. FlacoX says:

    nice… solved my problem

  38. Arvind says:

    Thanks!!

  39. GiftedHorse says:

    It’s just wonderful that this code is clear, concise and actually working on my device, so big thumbs up to the author/creator of this page to share this code.

    One addition that would make this page even better (ahem, and help me personally with my task at hand) is to post the code to catch a single/short press on any of the list items.

    Does anyone have a working example?

  40. sarah says:

    that’s what i was searching for my project..
    it’s great,,but when i try this code is there some script is not working like this script “R.array.menu” and “R.array.countries”
    may i know why..?
    can you help me..

  41. mikeplate says:

    @sarah Yes, those two names refers to array resource files in xml-format with the sample menu commands and countries in the list. The general format of such a file look like this http://developer.android.com/guide/topics/resources/more-resources.html#TypedArray

  42. Umesh says:

    Great tutorial.
    Just i want to know how to set background for particular item in context menu.
    Thanks in advance.

  43. RajaReddy says:

    Nice tutorial………….

  44. jlengrand says:

    Thx man ;)
    Saved me some hours

  45. [...] Show a context menu for long-clicks in an Android ListView [...]

  46. Daniel Marjamäki says:

    Great article. Short and simple to read. And it has all the info I needed.

  47. Saggio says:

    Nice Work!

  48. Christopher says:

    Thanks for this tutorial i used it to understand how contextmenu work and implemented it into my code with several changes to code.

  49. alguem says:

    Great tutorial.

  50. Xaviera says:

    Really helpful to me. Great tutorial.
    Thank you!

  51. Kofi says:

    excellent tutorial. very simple and understanding. Thank you

  52. Amazingly good article. You need to give some thought to writing full-time.
    Quick question though, how do you combat spam comments?
    My website is flooded each minute and my plugin is not
    doing a great job of sifting the good from the bad. Any tips?

  53. BalaVishnu says:

    gr8 1…very useful for me

  54. [...] @Override   public boolean onContextItemSelected(MenuItem item) {     switch (item.getItemId()) {       case DELETE_ID:         AdapterView.AdapterContextMenuInfo info=           (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();         delete(info.id);         return(true);     }     return(super.onOptionsItemSelected(item));   } Thats all… hope it helps.. Some references: http://developer.android.com/reference/android/widget/SimpleCursorAdapter.html http://www.mikeplate.com/2010/01/21/show-a-context-menu-for-long-clicks-in-an-android-listview/ [...]

  55. Thats Indeed very nice tutorial on android context menu
    you can also check the different kinds of menus in android and there purpose at
    Option Menu
    Context Menu
    Popup Menu

  56. akshay says:

    Great tutorial exactly what i was looking for.
    By the way, none of the images are displaying.

  57. Well explained, good work!

  58. eli says:

    great article ,Thanks a lot!

  59. tomaki says:

    thanks a lot!

  60. suraj says:

    how context menu consume the listview position.

  61. I read this paragraph fully on the topic of the
    comparison of most up-to-date and preceding technologies,
    it’s remarkable article.

    My webpage website builder online

Leave a Reply

Twitter: @mikeplate