【问题标题】:How can I refresh the ActionBar when onPrepareOptionsMenu switched menu entries?当 onPrepareOptionsMenu 切换菜单项时如何刷新 ActionBar?
【发布时间】:2011-12-07 14:07:26
【问题描述】:

在我的应用程序中,我经常启用/禁用菜单条目,并让它们在 onPrepareOptionsMenu 中可见。

今天我开始将 android:showAsAction 菜单属性添加到我的一些 Android 2.x 应用程序中,以在 ActionBar 上显示最常用的菜单条目。

ActionBar 不会立即反映启用/禁用和可见性。我需要点击右侧的下拉菜单才能看到这种变化。

好的,我知道菜单会触发 onPrepareOptionsMenu。但是我需要做什么来刷新 ActionBar?我认为需要从 onOptionsItemSelected 中应用此更改,但我不知道应该调用什么。

这是菜单:

<item
    android:icon="@drawable/ic_menu_mapmode"
    android:id="@+id/men_mapview"
    android:showAsAction="ifRoom|withText"
    android:title="@string/txt_mapview" />

<item
    android:icon="@drawable/ic_menu_mapmode"
    android:id="@+id/men_satelliteview"
    android:showAsAction="ifRoom|withText"
    android:title="@string/txt_satelliteview" />

这是 onPrepareOptionsMenu:

@Override
public boolean onPrepareOptionsMenu(final Menu menu) {
    MenuItem menuItemMapView = menu.findItem(R.id.men_mapview);
    MenuItem menuItemSatelliteView = menu.findItem(R.id.men_satelliteview);

    if (mapView.isSatellite()) {
        menuItemMapView.setEnabled(true).setVisible(true);
        menuItemmenuItemSatelliteView.setEnabled(false).setVisible(false);
    } else {
        menuItemMapView.setEnabled(false).setVisible(false);
        menuItemmenuItemSatelliteView.setEnabled(true).setVisible(true);
    }

    return super.onPrepareOptionsMenu(menu);
}

这是 onOptionsItemSelected

@Override
public boolean onOptionsItemSelected(final MenuItem menuItem) {
    switch (menuItem.getItemId()) {
        case R.id.men_mapview:
            mapView.setSatellite(false);
            mapView.setStreetView(true);
            mapView.invalidate();

            invalidateOptionsMenu(); // This works on Android 3.x devices only
            return true;
        case R.id.men_satelliteview:
            mapView.setSatellite(true);
            mapView.setStreetView(false);
            mapView.invalidate();

            invalidateOptionsMenu(); // This works on Android 3.x devices only
            return true;
    }

    return super.onOptionsItemSelected(menuItem);
}

编辑:如果我添加 invalidateOptionsMenu 这适用于 Android 3.x 应用程序,但由于缺少方法而在 Android 2.x 设备上崩溃。推荐的正确方法是什么?

【问题讨论】:

    标签: android menu android-actionbar


    【解决方案1】:

    我选择的方法是创建一个辅助类。例如:

    class VersionHelper
    {
        static void refreshActionBarMenu(Activity activity)
        {
            activity.invalidateOptionsMenu();
        }
    }
    

    现在在上面的代码中,将 invalidateOptionsMenu(); 替换为:

    if (Build.VERSION.SDK_INT >= 11)
    {
        VersionHelper.refreshActionBarMenu(this);
    }
    

    此方法归功于 CommonsWare(搜索 HoneycombHelper,并查看他的书籍 - 强烈推荐)

    【讨论】:

    • 你的回答和简单地在他最初调用 if (Build.VERSION.SDK_INT >= 11) { invalidateOptionsMenu(); }?您可以在 versionHelper 方法调用中粘贴版本检查吗?
    • @towpse 他将帮助程序类结构化的原因是为了避免由于非向后兼容性而导致的崩溃。 invalidateOptionsMenu() 方法仅存在于 API 11 (honeycomb) 及更高版本中。因此,如果您的应用程序要在低于 API 11 的任何设备上运行,它将崩溃。为避免这种情况,您将有问题的方法包装在另一个 static 方法(例如 refreshActionBarMenu())中,并且如果您在 API>11 上运行,调用此静态方法(因此在调用静态方法之前进行版本检查)。这是因为 VersionHelper 类在您实际使用之前不会加载。
    • @Turbo 好的,很酷,感谢您的解释,那么在其他情况下该怎么办?根本不更新菜单,或者如果用户运行的是旧操作系统,那么更新菜单项的旧方法是什么?
    • @towpse 我现在实际上正在弄清楚这种情况。我相信在else 这种情况下,您应该什么都不做。这是因为进行菜单更新的旧方法(API11 之前)是在方法onPrepareOptionsMenu 中,每次用户打开菜单时都会自动调用该方法。因此,要处理较旧的操作系统和较新的 API>11 的操作系统,请将菜单更改的代码放在 onPrepareOptionsMenu 中(这是处理旧操作系统),然后在发生事件时调用 invalidateOptionsMenu 来处理较新的操作系统会触发菜单更改。
    • 我的帮助类保护了旧的 SDK,那为什么不在它们里面做版本检查呢?
    【解决方案2】:

    保存对菜单的引用并调用:

    this.menu.clear();
    this.onCreateOptionsMenu(this.menu);
    

    【讨论】:

    • 这是关于如何在 API 11 之前的设备上以编程方式切换操作栏中选项菜单项的可见性的正确答案。
    【解决方案3】:

    基于上面的“Klaasvaak”答案。我正在使用它的子菜单。这对我有用:

    // Declare and save the menu as global, so it can be called anywhere.
    Menu absTopSubMenus;
    
    public boolean onCreateOptionsMenu(Menu menu) {
    
    absTopSubMenus = menu;  // Used for re-drawing this menu anywhere in the codes.
    
    // The remainder of your code below
    }
    

    然后,要重新绘制它,只需调用:

    // Redraw the top sub-menu
    absTopSubMenus.clear();
    onCreateOptionsMenu(absTopSubMenus);
    

    【讨论】:

    • 感谢它为我节省了很多时间!
    【解决方案4】:

    我不确定您是否已经看过它,但如果您广泛使用操作栏,并计划支持较低的 API (>8),请查看 actionBarSherlock 库。它将使您不必为较低和较高的 API 划分您的 actionBar 代码,然后您可以运行:

    runOnUiThread(new Runnable(){
      @Override
      public void run(){
        supportInvalidateOptionsMenu();
      }
    });
    

    【讨论】:

      【解决方案5】:

      感谢@Klaasvaak 向我们展示了这里的道路。我使用以下适用于 API 级别 11 之前和之后的内容:

      private void invalidOptionsMenuHelper() {
          if (Build.VERSION.SDK_INT >= 11) {
              invalidateOptionsMenu();
      
          } else if (mOptionsMenu != null) {
              mOptionsMenu.clear();
              onCreateOptionsMenu(mOptionsMenu);
          }
      }
      

      当然,您必须保存对我通过以下方式完成的菜单(在本例中为 mOptionsMenu)的引用:

      @Override
      public boolean onCreateOptionsMenu(Menu menu) {
          mOptionsMenu = menu;
      
          //... create and manage the menu normally
      }
      

      【讨论】:

        【解决方案6】:

        使用

        ActivityCompat.invalidateOptionsMenu(Activity activity)
        

        来自compatibility library

        见:https://stackoverflow.com/a/14748687/435855

        【讨论】:

        • 在 Gingerbread 上,调用此方法后不会调用 onCreateOptionsMenu()。
        • 是的。这是因为 preHoneycomb 不支持屏幕按钮,并且需要硬件菜单按钮。所以当用户按下菜单按钮时会调用 onCreateOptionMenu() 方法。 invalidateOptionsMenu 专注于刷新支持旧菜单硬件按钮的操作栏 3.0+。
        【解决方案7】:

        感谢接受的答案。我正在使用 ActionBarActivity。在这个类中你可以使用

        supportInvalidateOptionsMenu();
        

        【讨论】:

        • 给这个人一个 cookie.... 我不能将菜单的可见性设置为 false 的原因是我只使用了 invalidateOptionsMenu();直到我找到你的答案。谢谢老兄。
        • 这应该是选择的答案。
        • 由于 Toolbar 中的操作(图标)现在在内部由 TextView 而不是 ImageView 表示(我明白为什么),我不得不手动重新着色 TextView 内的复合可绘制对象,并另外分配一个 TouchListener按下/激活时重新着色。所以基本上我只是为图标着色。有类似情况的人吗?使菜单无效对我不起作用..
        • 此方法已弃用。
        【解决方案8】:

        您现在可以将 ActionbarActivity 中的 supportInvalidateOptionsMenu() 方法与支持库一起使用。所以你不必检查sdk的版本。直到 API 7 及更高版本。

        http://developer.android.com/reference/android/support/v7/app/ActionBarActivity.html

        这样做,您必须使用此导入支持库的 v7

        http://developer.android.com/tools/support-library/setup.html

        【讨论】:

          【解决方案9】:

          getActivity().invalidateOptionsMenu();

          完成工作。

          【讨论】:

            【解决方案10】:

            还要确保你没有打电话

            myAppCompatActivity.setToolbarTitle("some dynamic title");
            

            刷新菜单后不久。

            我遇到的问题是即使有显示空间,drawable 也不会显示。一旦我改变了方向,drawables就会出现......?

            总结:

            主活动:

            public class MainActivity extends AppCompatActivity {
            
                private boolean showMenu = true;
            
                public void setShowMenu(boolean show) {
                    showMenu = show;
                    supportInvalidateOptionsMenu();
                }
            
                @Override
                public boolean onCreateOptionsMenu(Menu menu) {
                    getMenuInflater().inflate(R.menu.my_menu, menu);
                    menu.findItem(R.id.menu_share).setVisible(showMenu);
                    // menu.findItem(...
                    return true;
                }
            }
            

            FragmentNoMenu:

            public abstract class FragmentNoMenu extends Fragment {
            
                protected MainActivity mainActivity;
            
                @Override
                public void onCreate(Bundle savedInstanceState) {
                    super.onCreate(savedInstanceState);
                    setHasOptionsMenu(true);
                    mainActivity = (MainActivity) getActivity();
                    if (mainActivity != null) {
                        mainActivity.setShowMenu(false);
                    }
                }
            
            }
            

            FragmentWithMenu:

            public abstract class FragmentWithMenu extends Fragment {
            
                protected MainActivity mainActivity;
            
                @Override
                public void onCreate(Bundle savedInstanceState) {
                    super.onCreate(savedInstanceState);
                    setHasOptionsMenu(true);
                    mainActivity = (MainActivity) getActivity();
                    if (mainActivity != null) {
                        mainActivity.setShowMenu(true);
                    }
                }
            
            }
            

            【讨论】:

              猜你喜欢
              • 2018-08-13
              • 1970-01-01
              • 2018-07-01
              • 2011-08-11
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多