首页 文章

如何在多片段活动中处理onContextItemSelected?

提问于
浏览
67

我目前正在尝试调整我的应用程序以使用“适用于Android v4的兼容性库”,以便为Android 1.6用户提供使用片段的好处 .

上下文菜单的实现似乎很棘手:

  • 应用程序的主要活动是扩展 FragmentActivity 类 .

  • 这些片段都基于一个扩展Fragment类的类 .

  • 片段类在其 onCreateView() 方法中调用 registerForContextMenu() 并覆盖方法 onCreateContextMenu()onContextItemSelected() .

对于 onCreateContextMenu() ,这非常有效 . 上下文菜单从资源文件中膨胀,并根据所选项目进行略微修改(基于listView ...即使片段不是ListFragment) .

选择上下文菜单项时会发生此问题 . 从第一个添加的片段开始,为所有当前存在的片段调用 onContextItemSelected() .

在我的例子中,片段用于显示文件夹结构的内容 . 当打开子文件夹片段的上下文菜单并选择菜单项时,首先在上层调用 onContextItemSelected() (取决于此时允许/可见的片段数) .

现在,我使用活动级别上的字段的变通方法,该字段保存最后一个片段的标记,调用它的 onCreateContextMenu() . 这样,当存储的标记与getTag()不同时,我可以在 onContextItemSelected() 的开头调用"return super.onContextItemSelected(item)" . 但这种方法对我来说有点脏 .

为什么在所有片段上调用onContextItemSelected()?而不仅仅是一个叫 onCreateContextMenu() 的人?

处理这个问题最优雅的方法是什么?

11 回答

  • 1

    即使您找到了解决方法,我也会发布一个答案,因为我刚刚处理了类似的问题 . 当您为特定片段的上下文菜单充气时,为每个菜单项分配一个对片段唯一的groupId . 然后在'onContextItemSelected'中测试groupId . 例如:

    public void onCreateContextMenu(ContextMenu menu, View v,ContextMenuInfo menuInfo) {
        menu.add(UNIQUE_FRAGMENT_GROUP_ID, MENU_OPTION_1, 0, R.string.src1);
        menu.add(UNIQUE_FRAGMENT_GROUP_ID, MENU_OPTION_2, 0, R.string.src2);
    }
    public boolean onContextItemSelected(MenuItem item) {
        //only this fragment's context menus have group ID of -1
        if (item.getGroupId() == UNIQUE_FRAGMENT_GROUP_ID) {
            switch(item.getItemId()) {
            case MENU_OPTION_1: doSomething(); break;
            case MENU_OPTION_2: doSomethingElse(); break;
        }
    }
    

    这样,所有片段仍将接收对'onContextItemSelected'的调用,但只有正确的片段才会响应,因此无需编写活动级代码 . 我假设即使您没有使用'menu.add(...)',此技术的修改版本也可以工作

  • 0

    另一个解决方案:

    @Override
    public boolean onContextItemSelected(MenuItem item) {
        if (getUserVisibleHint()) {
            // context menu logic
            return true;
        }
        return false;
    }
    

    基于杰克沃顿的this patch .

  • 8

    我喜欢Sergei G的简单解决方案(基于Jake Wharton的修复),但因为更容易添加到几个片段中而倒置了:

    public boolean onContextItemSelected(android.view.MenuItem item) 
    {  
        if( getUserVisibleHint() == false ) 
        {
            return false;
        }
    
        // The rest of your onConextItemSelect code
        AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
     }
    

    之后,代码与之前相同 .

  • 0

    我发现了一个非常简单的解决方案 . 每次创建ContextMenu时都会调用onCreateContextMenu(),我将布尔变量设置为true .

    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);
        MenuInflater inflater = getActivity().getMenuInflater();
        inflater.inflate(R.menu.film_menu, menu);
        bMenu=true;
    }
    

    我唯一需要做的就是要求变量OnContextItemSelected()

    public boolean onContextItemSelected(MenuItem item) {
        if (bMenu) {
            bMenu=false;
            if (item.getItemId() == R.id.filmProperties) {
                ///Your code
                return true;
            } else {
                return super.onContextItemSelected(item);
            }
        } else {
            return super.onContextItemSelected(item);
        }
    }
    

    而已 .

  • 2

    我找到了另一种选择 . 它没有改变我上面的问题,但它使它毫无意义 .

    我已从我的应用程序中完全删除了上下文菜单 . 相反,我在列表项上捕获longclick并在此时更改操作栏的可见按钮 . 从用户的角度来看,这更像平板电脑,就像上下文菜单一样 .

    在向后兼容的应用程序中,操作栏不存在 . 所以我决定为Honeycomb之前的设备构建我自己的(顶部的工具栏) .

    如果您想继续使用上下文菜单,我找不到更好的解决方案作为我上面提到的解决方法 .

  • 4

    在我的第一个片段中,我设置了所有菜单ID> 5000,因为作为onContextItem的第一行代码我选择了第一个片段

    if (item.getItemId() < 5000) return false;
    

    并将调用第二个片段 .

  • 54

    如果您在片段中使用带有listview的适配器,这可能会有所帮助 .

    public boolean onContextItemSelected(final MenuItem item) {
        final AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
    
        //Check if the context menu call came from the list in this fragment (needed for support for multiple fragments in one screen)
        if (info.targetView.getParent() != getView().findViewById(android.R.id.list))
            return super.onContextItemSelected(item);
    
        //Handle context menu item call
        switch (item.getItemId()) {
            ...
        }
    }
    
  • 1

    只是改变

    @Override
        public boolean onContextItemSelected(MenuItem item) {
        return true;
     }
    

    @Override
        public boolean onContextItemSelected(MenuItem item) {
        return super.onContextItemSelected(item); 
     }
    

    并且会很棒!!!

  • 0

    恕我直言,我们可以检查目标视图是否是片段列表视图的子项 . 这很简单,对我很有帮助 . 我刚刚添加到我的所有片段:从旧API迁移时 if (getListView.getPositionForView(info.targetView) == -1) return false

    这是我的一个父片段的示例 . 这是Scala,但我希望你有个主意 .

    @Loggable
    override def onContextItemSelected(menuItem: MenuItem): Boolean = {
      for {
        filterBlock <- TabContent.filterBlock
        optionBlock <- TabContent.optionBlock
        environmentBlock <- TabContent.environmentBlock
        componentBlock <- TabContent.componentBlock
      } yield menuItem.getMenuInfo match {
      case info: AdapterContextMenuInfo =>
        if (getListView.getPositionForView(info.targetView) == -1)
          return false
        TabContent.adapter.getItem(info.position) match {
          case item: FilterBlock.Item =>
            filterBlock.onContextItemSelected(menuItem, item)
          case item: OptionBlock.Item =>
            optionBlock.onContextItemSelected(menuItem, item)
          case item: EnvironmentBlock.Item =>
            environmentBlock.onContextItemSelected(menuItem, item)
          case item: ComponentBlock.Item =>
            componentBlock.onContextItemSelected(menuItem, item)
          case item =>
            log.debug("skip unknown context menu item " + info.targetView)
            false
        }
      case info =>
        log.fatal("unsupported menu info " + info)
        false
      }
    } getOrElse false
    

    附:如果你跟踪onContextItemSelected(...)的调用,你可以通知 super.onContextItemSelected(item) 总是返回 false . 有效的onContextItemSelected被调用 AFTER, not WITHIN . 所以 super.onContextItemSelected(item) 没用,我用 false 替换了它 .

  • 68

    我找到了比暴露更简单的解决方案:

    public boolean onContextItemSelected(MenuItem item) {
        ListView yourList = (ListView) (ListView) getView().findViewById(R.id.yourList);
    
        if (!yourList.hasFocus())
            return false;
    
        switch(item.getItemId()) {
            ...
        }
    }
    
  • 0

    在方法中改变返回true;回来super.onContextItemSelected(项目);在我的onContextItemSelected()覆盖中,一切都开始工作了 .

相关问题