android view selected,Identifying the view selected in a ContextMenu (Android)

本文讨论了在Android中处理ContextItemSelected回调时如何确定被点击的菜单项,包括通过MenuItem.getId()、AdapterView.AdapterContextMenuInfo、自定义View实现和利用groupId区分选项。作者提供了多种解决方案并分析了各自的优缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

In Android, onContextItemSelected has a single MenuItem argument and so it isn't clear how to identify the view selected. MenuItem.getMenuInfo provides access to Contextmenu.ContextMenuInfo, but while both known subclasses provide access to the target view, there does not appear to be an accessor on the interface.

One alternative is to save the View provided in onCreateContextMenu in a private class variable which relies on onCreateContextMenu not being called again in the activity before onContextItemSelected. Another is to use the id of the View for the itemId argument of ContextMenu.add. If we do this, we would then need to identify the option selected from the context menu by using its (possibly internationalised) title.

What is the best method for identifying the View selected in onContextSelected?

# Answer 1

4d350fd91e33782268f371d7edaa8a76.png

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.

# Answer 2

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.

# Answer 3

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);

}

# Answer 4

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!

# Answer 5

In case you are attaching ContextMenus to multiple Views which are NOT in a ListView (that is there is no adapter underlying the Views) and you wish to determine which View was long-pressed to access the ContextMenu the following "hack" can be implemented. (It would be better if Android provided a listener that could be associated with each item).

The "hack" is that one creates a private View member mLastViewTouched in the class and then attach the following onTouchListener to all Views that can generate a ContextMenu:

private View.OnTouchListener onTouchListener = new View.OnTouchListener() {

@Override

public boolean onTouch(View view, MotionEvent motionEvent)

{

mLastViewTouched = view; // Store a handle on the last view touched. This will be used to identify the view on which the Context Menu was launched

return false; // We return false since this indicates that the touch was not handled and so it is passed down the stack to be handled appropriately

}

};

So whenever a View is touched mLastViewTouched is updated. Now in onContextItemSelected you will have access to the View that initiated the ContextMenu.

# Answer 6

When constructing your menu in OnCreateContextMenuListener or public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) implementation, you can set a custom MenuItem.OnMenuItemClickListener for each item:

addPhotosBtn.setOnCreateContextMenuListener((menu, v, menuInfo) -> {

getMenuInflater().inflate(R.menu.upload_image_menu, menu);

int itemCount = menu.size();

for(int i = 0; i < itemCount; i++) {

menu.getItem(i).setOnMenuItemClickListener(addPhotosBtnMenuItemClickListener);

}

});

Since at this time you have access to the view for which you are creating the context menu, you can tightly couple the listener with that view.

# Answer 7

Here is what I did to distinguish between 2 listviews lstA and lstB MenuItem

@Override

public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {

super.onCreateContextMenu(menu, v, menuInfo);

int startid = (v.getId() == R.id.lstA) ? 0 : 2; //0-1 will be lstA and 2-3 will be lstB

menu.setHeaderTitle("some title");

menu.add(Menu.NONE, startid, Menu.NONE, "Item 1");

menu.add(Menu.NONE, startid+1, Menu.NONE, "Item 2");

}

@Override

public boolean onContextItemSelected(MenuItem item) {

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

int menuItemIndex = info.position;

switch(item.getItemId()) {

case 0:

break;

case 1:

break;

case 2:

break;

case 3:

break;

}

return true;

}

# Answer 8

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值