Как я могу обновить ActionBar, когда onPrepareOptionsMenu переключил пункты меню?

В моих приложениях я часто включаю / отключаю пункты меню и делаю их видимыми из onPrepareOptionsMenu.

Сегодня я начал добавлять атрибут меню android:showAsAction в некоторые из моих приложений для Android 2.x, чтобы отображать элементы меню, наиболее часто используемые в ActionBar.

Панель действий не отражает включение / отключение и видимость сразу. Мне нужно нажать на выпадающее меню справа, чтобы увидеть это изменение.

Хорошо, я понимаю, что меню запускается по меню "RepareOptionsMenu". Но что мне нужно сделать, чтобы обновить 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" />

Вот меню onPrepareOptions:

@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 из-за отсутствия метода. Какой рекомендуемый способ сделать это правильно?

10 ответов

Решение

Мой метод выбора - создать вспомогательный класс. Например:

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

Теперь в вашем коде выше, замените invalidateOptionsMenu(); с:

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

Кредит на этот метод идет на CommonsWare (поиск HoneycombHelper и проверить его книги - настоятельно рекомендуется)

Спасибо за принятый ответ. Я использую ActionBarActivity. в этом классе вы можете использовать

supportInvalidateOptionsMenu();

Сохранить ссылку в меню и вызвать:

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

Теперь вы можете использовать метод supportInvalidateOptionsMenu() из ActionbarActivity с библиотекой поддержки. Так что вам не нужно проверять версию SDK. Идет до API 7 и выше.

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

сделать так, вы должны импортировать v7 библиотеки поддержки, используя эту

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

На основании "Клаасваак" ответ выше. Я использую его подменю. Это работает для меня:

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

Я не уверен, что вы уже видели это, но если вы широко используете панель действий и планируете поддерживать более низкие API (>8), взгляните на библиотеку actionBarSherlock. Это сделает так, что вам не придется разделять код actionBar на более низкие и более высокие API, а затем вы можете просто запустить:

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

. GetActivity() invalidateOptionsMenu();

выполняет свою работу

Престижность @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
}

Также убедитесь, что вы не звоните

myAppCompatActivity.setToolbarTitle("some dynamic title");

вскоре после того, как вы обновили свое меню.

У меня была проблема, что ничьи не отображались, даже если бы было место для их отображения. После того, как я изменил ориентацию, появились чертежи..?

В итоге:

Основная деятельность:

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

}
Другие вопросы по тегам