识别在ContextMenu(Android)中选择的视图

在Android中, onContextItemSelected有一个MenuItem参数,因此不清楚如何识别所选的视图。 MenuItem.getMenuInfo提供对Contextmenu.ContextMenuInfo的访问,但是虽然两个已知的子类都提供对目标视图的访问,但接口上似乎没有访问者。

另一种方法是将onCreateContextMenu中提供的View保存在私有类variables中,该variables依赖onCreateContextMenuonContextItemSelected之前的活动中不再被调用。 另一种方法是使用View的id作为ContextMenu.add的itemId参数。 如果我们这样做,那么我们需要通过使用其(可能是国际化的)标题来识别从上下文菜单中选择的选项。

识别onContextSelected所选View的最佳方法是什么?

对于Android中的选项菜单或上下文菜单,没有“识别所选视图”的概念。 因此,回答你的问题相当困难。 所以,我会做一些猜测。

如果通过“识别所选视图”,则表示选择了哪个菜单选项,即传递给onOptionsItemSelected()onContextItemSelected()MenuItem上的getItemId() onContextItemSelected()

如果通过“识别所选视图”意味着ListView中的哪一行是长按以显示上下文菜单的getMenuInfo()getMenuInfo() (在MenuItem上调用)转换为AdapterView.AdapterContextMenuInfo ,然后使用id或根据您的适配器适当的position值。 请参阅此处以获取使用此技术的示例项目 。

如果通过“识别所选视图”意味着您在活动中有多个非ListView上下文菜单,我将不会使用该UI技术。

上下文菜单的重点在于它与单个底层视图相关联,并且Android中的设计限制显然是在回调“onContextItemSelected”中丢失了关联。 在足够大小的任何视图上启用长触摸似乎是完全合理的替代鼠标右键单击。

正如其他post所建议的那样,在某些情况下:

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

是合适的,targetView是一个有用的参考点。

另一种方法是对视图进行子类化并覆盖’getContextMenuInfo’以提供视图引用。 例如,一个简单的TextView:

包...;

公共类TextViewWithContext扩展TextView {
     TextViewContextMenuInfo _contextMenuInfo = null;

     public TextViewWithContext(Context context){
        超级(上下文);
         _contextMenuInfo = new TextViewContextMenuInfo(this);
     }

     public TextViewWithContext(Context context,AttributeSet attrs){
        超级(环境,attrs);
         _contextMenuInfo = new TextViewContextMenuInfo(this);
     }   

     protected ContextMenuInfo getContextMenuInfo(){
         return _contextMenuInfo;
     }

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

     protected class TextViewContextMenuInfo实现ContextMenuInfo {
         protected TextView _textView = null;

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

 ...
     @覆盖
     public boolean onContextItemSelected(MenuItem item){   

         ContextMenuInfo menuInfo = item.getMenuInfo();

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

最后,如果基类View类已经为视图指定了一个反向引用的ContextInfo对象,而不是目前的null,那将会更有帮助。

class TestActivity扩展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); } 

如果您将ContextMenus附加到不在ListView中的多个视图(即视图中没有适配器),并且您希望确定哪个View长按以访问ContextMenu,则可以实现以下“hack”。 (如果Android提供了可以与每个项目相关联的监听器,那会更好)。

“hack”是在类中创建一个私有View成员mLastViewTouched ,然后将以下onTouchListener附加到可以生成ContextMenu的所有Views:

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

因此,只要触摸了视图,就会更新mLastViewTouched 。 现在在onContextItemSelected您将可以访问启动ContextMenu的View。

我通过根据发送它的项目为MenuItem设置groupID来修复类似的问题,例如:

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

这将允许您在onContextItemSelected中获取groupID:

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

您不必使用资源ID – 您可以使用任何您想要的int。 适合我!

OnCreateContextMenuListenerpublic void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo)实现中public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo)可以为每个项目设置自定义MenuItem.OnMenuItemClickListener

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

由于此时您可以访问要为其创建上下文菜单的视图,因此可以将侦听器与该视图紧密耦合。

这是我做的区分2个列表视图lstA和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; }