onPrepareOptionsMenu 切换菜单项时如何刷新 ActionBar?

发布于 2024-12-09 16:47:12 字数 2225 浏览 2 评论 0 原文

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

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

ActionBar 不会立即反映启用/禁用和可见性。我需要单击右侧的菜单下拉菜单才能看到此更改的发生。

好的,我确实知道菜单会在PrepareOptionsMenu 上触发。但是我需要做什么来刷新 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 设备上崩溃。推荐的正确方法是什么?

Within my apps I often enable/disable menu entries and do make them visible from onPrepareOptionsMenu.

Today I started to add the android:showAsAction menu attribute to some of my Android 2.x apps to show menu entries used most on the ActionBar.

The ActionBar does not reflect the enable/disable and visibility immediately. I need to click on the menu dropdown on the right to see this change happen.

Ok, I do understand that the menu fires onPrepareOptionsMenu. But what do I need to do to refresh the ActionBar? I think this change needs to be applied from within onOptionsItemSelected but I don't know what I should call.

Here's the menu:

<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" />

Here's the 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);
}

Here's the 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);
}

EDIT: If I add invalidateOptionsMenu this works on Android 3.x apps but crashes on Android 2.x devices because of a missing method. What's the recommended way to do it right?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

你怎么敢 2024-12-16 16:47:13

getActivity().invalidateOptionsMenu();

完成工作。

getActivity().invalidateOptionsMenu();

gets the job done.

享受孤独 2024-12-16 16:47:13

感谢@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
}

Kudos to @Klaasvaak for showing us the way here. I use the following which works on both pre- and post- API Level 11:

private void invalidOptionsMenuHelper() {
    if (Build.VERSION.SDK_INT >= 11) {
        invalidateOptionsMenu();

    } else if (mOptionsMenu != null) {
        mOptionsMenu.clear();
        onCreateOptionsMenu(mOptionsMenu);
    }
}

Of course, you must save a reference to the menu (mOptionsMenu in this case) which I accomplish via:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    mOptionsMenu = menu;

    //... create and manage the menu normally
}
霓裳挽歌倾城醉 2024-12-16 16:47:13

还要确保您

myAppCompatActivity.setToolbarTitle("some dynamic title");

刷新菜单后不会立即打电话。

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

总结:

MainActivity:

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

}

Also make sure you are not calling

myAppCompatActivity.setToolbarTitle("some dynamic title");

shortly after you have refreshed your menu.

I had the issue that the drawables would not show up even if there was room for them to be displayed. Once I did an orientation change the drawables then appeared.. ?

In Summary:

MainActivity:

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

}
廻憶裏菂餘溫 2024-12-16 16:47:12

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

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

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

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

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

My method of choice is to create a helper class. For example:

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

Now in your code above, replace invalidateOptionsMenu(); with:

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

Credit for this method goes to CommonsWare (search for HoneycombHelper, and check out his books - highly recommended)

谈情不如逗狗 2024-12-16 16:47:12

感谢已接受的答案。我正在使用 ActionBarActivity。在这堂课中你可以使用

supportInvalidateOptionsMenu();

Thanks to the accepted answer. I am using ActionBarActivity. in this class you can use

supportInvalidateOptionsMenu();
ㄟ。诗瑗 2024-12-16 16:47:12

使用

ActivityCompat.invalidateOptionsMenu(Activity activity)

兼容性库

请参阅:https://stackoverflow.com/a/14748687/435855

Use

ActivityCompat.invalidateOptionsMenu(Activity activity)

from the compatibility library.

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

送你一个梦 2024-12-16 16:47:12

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

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

save a reference to the menu and call:

this.menu.clear();
this.onCreateOptionsMenu(this.menu);
情释 2024-12-16 16:47:12

基于上面的“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);

Based on "Klaasvaak" answer above. I am using its subMenus. This works for me :

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

Then, to re-draw this, just call :

// Redraw the top sub-menu
absTopSubMenus.clear();
onCreateOptionsMenu(absTopSubMenus);
尸血腥色 2024-12-16 16:47:12

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

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

为此,您必须使用此

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

You can now use supportInvalidateOptionsMenu() method from the ActionbarActivity with the support library. So you don't have to check for the version of the sdk. Goes until API 7 and above.

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

do to so, you have to import the v7 of the support library using this

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

聊慰 2024-12-16 16:47:12

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

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

I am not sure you have seen it already, but if you use the actionbar extensively, and plan on supporting lower API's (>8), take a look at the actionBarSherlock library. It will make it so you do not have to section your actionBar code for lower and Higher API's, and then you can just run:

runOnUiThread(new Runnable(){
  @Override
  public void run(){
    supportInvalidateOptionsMenu();
  }
});
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文