Identifying the view selected in a ContextMenu (Android)

There is no such concept as "identifying the View selected" for either option menus or context menus in Android. Hence, it is rather difficult to answer your question. So, I'll take some guesses.

If by "identifying the View selected" you mean which menu choice was selected, that is getItemId() on the MenuItem that is passed to onOptionsItemSelected() or onContextItemSelected().

If by "identifying the View selected" you mean which row in a ListView was the one long-tapped on to bring up the context menu, cast getMenuInfo() (called on the MenuItem) to AdapterView.AdapterContextMenuInfo, then use either the id or the position values as appropriate based on your adapter. See here for a sample project that uses this technique.

If by "identifying the View selected" you mean you have more than one non-ListView context menu in an activity, I would not use that UI technique.


class TestActivity extends Activity {

// create temp item here

private ImageView tmpImageView = null;

...

public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo){
    super.onCreateContextMenu(menu, v, menuInfo);
    // initialize temp item
    mCurrentStatusImage = (ImageView) v.findViewById(R.id.rule_status);
}

public boolean onContextItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case ENABLE_ID:
            // use temp item
            tmpImageView.setImageResource(android.R.drawable.presence_online);
            return super.onContextItemSelected(item);
        case DISABLE_ID:
            // use temp item
            tmpImageView.setImageResource(android.R.drawable.presence_invisible);
            return super.onContextItemSelected(item);
        default:    
            return super.onContextItemSelected(item);
 }

I fixed a similar problem by setting a groupID for the MenuItem based on which item sent it e.g:

    textview.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
        @Override
        public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo contextMenuInfo) {
                menu.setHeaderTitle("Context Menu");
                menu.add(R.id.whateverviewclicked, RENAME_MENU_ITEM, 0, "Rename");
                menu.add(R.id.whateverviewclicked, DELETE_MENU_ITEM, 1, "Delete");
             }
         });

This would allow you to get the groupID in the onContextItemSelected:

public boolean onContextItemSelected(MenuItem aItem) {
        int selectedViewID = aItem.getGroupId();
        int selectedItem = aItem.getItemId();
};

you don't have to use the resource ID - you can use any int you want. Works for me!


The whole point of a context menu is that it is associated with an individual underlying view, and it is clearly a design limitation in Android that the association is lost in the callback 'onContextItemSelected'. Enabling long-touch on any view of sufficient size seems perfectly reasonable as an alternative to a right mouse click.

As other posts have recommended, for some contexts:

AdapterView.AdapterContextMenuInfo menuInfo = 
(AdapterView.AdapterContextMenuInfo)item.getMenuInfo();

is appropriate and the targetView is a useful reference point.

Another way is to subclass the view and override 'getContextMenuInfo' to provide the view reference. For example, a simple TextView:

package ...;

public class TextViewWithContext extends TextView {
    TextViewContextMenuInfo _contextMenuInfo = null;

    public TextViewWithContext(Context context) {
        super(context);
        _contextMenuInfo = new TextViewContextMenuInfo(this);
    }

    public TextViewWithContext(Context context, AttributeSet attrs) {
        super(context, attrs);
        _contextMenuInfo = new TextViewContextMenuInfo(this);
    }   

    protected ContextMenuInfo getContextMenuInfo() {
        return _contextMenuInfo;
    }

    public boolean isContextView(ContextMenuInfo menuInfo) {
        return menuInfo == (ContextMenuInfo)_contextMenuInfo;
    }

    protected class TextViewContextMenuInfo implements ContextMenuInfo {
        protected TextView  _textView = null;

        protected TextViewContextMenuInfo(TextView textView) {
            _textView = textView;
        }
    }
}

...
    @Override
    public boolean onContextItemSelected(MenuItem item) {   

        ContextMenuInfo menuInfo = item.getMenuInfo();

        if (textViewWithContext.isContextView(menuInfo) {
            ...
        }
    }

Finally, it would have been more helpful if the base View class had assigned a ContextInfo object with a reverse reference to the view, rather than null as at present.

Tags:

Android