【问题标题】:How to update a menu item shown in the ActionBar?如何更新 ActionBar 中显示的菜单项?
【发布时间】:2011-08-11 16:10:15
【问题描述】:

我有一个包含 2 个片段的 Activity。两者都是 ListFragments 并且都将 MenuItems 贡献给菜单。我有一个 MenuItem,我设置了属性 android:showAsAction 让它显示为 ActionBar 上的一个按钮。效果很好。

现在 MenuItem 依赖于状态。这是一个暂停/恢复菜单选项,用于暂停和恢复队列。我的问题是我不知道在创建 Fragment 时如何设置它的初始状态。

它的状态取决于队列是否暂停。所以我有一个 AsyncTask 获取队列并根据队列的状态设置一个布尔值(暂停)。我正在调用 onPrepareOptionsMenu 以根据队列的最后一个已知状态设置暂停菜单项的文本,如果我将 MenuItem 留在实际菜单中,这将非常有用。您点击菜单图标并触发 onPrepareOptionsMenu 并在显示之前更新菜单。

问题是,如果我将相同的 MenuItem 放在 ActionBar (showAsAction) 上,如何强制它更新而无需调用 onPrepareOptionsMenu?我需要能够做到这一点,因为在第一次启动应用程序时,我发送了一个获取队列的请求,但是在设置并显示 ActionBar 后任务返回。我在我的片段中创建了一个处理程序,每次我获得队列更新时都会调用它,但是从那里,我如何更新 ActionBar 上的 MenuItem 的文本?除了 onPrepareOptionMenu 之外,我似乎找不到一种方法来获取当前设置的菜单来操作它。

罗伯·W.

【问题讨论】:

    标签: android menu android-fragments android-actionbar


    【解决方案1】:

    选项#1:试试invalidateOptionsMenu()。我不知道这是否会强制立即重绘操作栏。

    选项#2:查看getActionView() 是否为受影响的MenuItem 返回任何内容。 showAsAction 可能只是自动为您创建操作视图。如果是这样,您大概可以启用/禁用View。

    除了 onPrepareOptionMenu 之外,我似乎无法找到一种方法来获取当前设置的菜单来操作它。

    你可以挂在Menu你收到onCreateOptionsMenu()的对象上。引用docs:

    您可以安全地保留菜单(以及从中创建的任何项目),根据需要对其进行修改,直到下次调用 onCreateOptionsMenu()。

    【讨论】:

    • 尝试了选项#1,这成功了。由于我试图在来自单独线程的回调中更新 UI,因此它引发了异常,因为我实际上不在 UI 线程上。为了解决这个问题,我创建了一个处理程序,并在调用回调时向处理程序发送了一条刷新消息。但最终我使用 getActivity().invalidateOptionsMenu() 来刷新菜单。
    • @brockoli:啊,好!鉴于该方法的 Javadocs 措辞,我怀疑它是否会产生预期的效果,尽管这似乎是他们首先将其添加到 API 级别 11 的原因。很高兴听到它对您有用!
    • 我一直在努力想办法解决这个问题,它就像一个魅力!
    • 如果您使用的是支持库,请改用supportInvalidateOptionsMenu()
    • @TimKist, supportInvalidateOptionsMenu() 现在已弃用;你可以放心地使用invalidateOptionsMenu()。
    【解决方案2】:

    在我的情况下:invalidateOptionsMenu 只是将文本重新设置为原始文本, 但直接访问菜单项并重写所需文本没有问题:

    if (mnuTopMenuActionBar_ != null) {
        MenuItem mnuPageIndex = mnuTopMenuActionBar_
            .findItem(R.id.menu_magazin_pageOfPage_text);
    
        if (mnuPageIndex != null) {
            if (getScreenOrientation() == 1) {
                mnuPageIndex.setTitle((i + 1) + " von " + pages);
            }
            else {
                mnuPageIndex.setTitle(
                    (i + 1) + " + " + (i + 2) + " " + " von " + pages);
            }
            // invalidateOptionsMenu();
        }
    }
    

    由于下面的评论,我能够通过以下代码访问菜单项:

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.magazine_swipe_activity, menu);
        mnuTopMenuActionBar_ = menu;
        return true;
    }
    

    【讨论】:

    • 您是如何使用mnuTopMenuActionBar_ 获得ActionBar 视图的句柄的?
    • 当操作栏被初始化时,我将视图保存到一个成员变量中......就像这样:@Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.magazine_swipe_activity,菜单); mnuTopMenuActionBar_ = 菜单;返回真; }
    • 这样做,您可能会遇到同步问题,对吧?我是说。您不确切知道 onCreateOptionMenu 何时运行,因此您可能会使用未初始化的mnuTopMenuActionBar_ 来访问您的代码,对吗?你会如何解决这个问题?
    • 嘿,如果使用了actionbar(是的,就是这样)这个方法总是被调用,所以没有问题......(直接在活动开始时)stackoverflow.com/questions/7705927/…
    【解决方案3】:

    我用过这段代码:

    public boolean onPrepareOptionsMenu (Menu menu) {       
        MenuInflater inflater = getMenuInflater();
        TextView title  = (TextView) findViewById(R.id.title);
        menu.getItem(0).setTitle(
            getString(R.string.payFor) + " " + title.getText().toString());
        menu.getItem(1).setTitle(getString(R.string.payFor) + "...");
        return true;        
    }
    

    对我来说就像一个魅力,你可以找到 OnPrepareOptionsMenu here

    【讨论】:

    • 这里的 MenuInflater 的目的是什么?
    • 这太棒了
    【解决方案4】:

    为了清楚起见,我认为可以从以下内容中显示一个抓取资源的直接示例,我认为这有助于通过一个快速的直接示例来回答这个问题。

    private MenuItem menuItem_;
    
    @Override
    public boolean onCreateOptionsMenu(Menu menuF) 
    {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.menu_layout, menuF);
        menuItem_ = menuF.findItem(R.id.menu_item_identifier);
        return true;
    }
    

    在这种情况下,您在开始时保留一个 MenuItem 引用,然后在稍后的给定时间点更改它的状态(例如图标状态更改)。

    【讨论】:

      【解决方案5】:

      首先请按照两行代码更新操作栏项 在此之前,您应该在 oncreateOptionMenu() 中设置一个条件。 例如:

      Boolean mISQuizItemSelected = false;
      
      /**
       * Called to inflate the action bar menus
       *
       * @param menu
       *      the menu
       *
       * @return true, if successful
       */
      
      @Override
      public boolean onCreateOptionsMenu(Menu menu) {
      
          // Inflate the menu items for use in the action bar
      
          inflater.inflate(R.menu.menu_demo, menu);
      
          //condition to hide the menus
          if (mISQuizItemSelected) {
              for (int i = 0; i < menu.size(); i++) {
                  menu.getItem(i).setVisible(false);
              }
          }
      
          return super.onCreateOptionsMenu(menu);
      }
      
      /**
       * Called when the item on the action bar being selected.
       *
       * @param item
       *      menuitem being selected
       *
       * @return true if the menuitem id being selected is matched
       * false if none of the menuitems id are matched
       */
      @Override
      public boolean onOptionsItemSelected(MenuItem item) {
          if (item.getId() == R.id.action_quiz) {
              //to navigate based on the usertype either learner or leo
              mISQuizItemSelected = true;
      
              ActionBar actionBar = getActionBar();
              invalidateOptionMenu();
          }
      }
      

      【讨论】:

        【解决方案6】:

        要从 Fragment 刷新菜单,只需调用:

        getActivity().invalidateOptionsMenu();
        

        【讨论】:

          【解决方案7】:

          在 Kotlin 1.2 中只需调用:

          invalidateOptionsMenu()
          

          onCreateOptionsMenu 函数将被再次调用。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-11-29
            • 1970-01-01
            • 1970-01-01
            • 2013-08-24
            • 1970-01-01
            相关资源
            最近更新 更多