Jak zaktualizować element menu wyświetlany na pasku akcji?


94

Mam działanie, które ma 2 fragmenty. Oba są ListFragments i oba współtworzą MenuItems do Menu. Mam jeden element MenuItem, dla którego ustawiłem atrybut android: showAsAction, aby był wyświetlany jako przycisk na pasku akcji. Co działa dobrze.

Teraz MenuItem jest zależne od stanu. Jest to opcja menu Wstrzymaj / Wznów do wstrzymywania i wznawiania kolejki. Mój problem polega na tym, że nie potrafię wymyślić, jak ustawić jego początkową statuę podczas tworzenia fragmentu.

Jego stan zależy od tego, czy kolejka jest wstrzymana, czy nie. Mam więc AsyncTask, który pobiera kolejkę i ustawia wartość logiczną (wstrzymaną) na podstawie stanu kolejki. Wzywam onPrepareOptionsMenu, aby ustawić tekst dla pozycji menu Pauza na podstawie ostatniego znanego stanu kolejki i działa to świetnie, jeśli zostawię MenuItem w rzeczywistym menu. Dotykasz ikony menu, a onPrepareOptionsMenu jest uruchamiane, a menu jest aktualizowane przed wyświetleniem.

Problem polega na tym, że jeśli umieszczę to samo MenuItem na ActionBar (showAsAction), jak mogę zmusić go do aktualizacji bez konieczności wywoływania onPrepareOptionsMenu? Muszę to zrobić, ponieważ przy pierwszym uruchomieniu aplikacji wysyłam żądanie pobrania kolejki, ale zadanie wraca po skonfigurowaniu i wyświetleniu ActionBar. Utworzyłem procedurę obsługi w moim fragmencie, która jest wywoływana za każdym razem, gdy otrzymuję aktualizację kolejki, ale w jaki sposób mogę zaktualizować tekst mojego elementu MenuItem na ActionBar? Wydaje się, że nie mogę znaleźć sposobu na pobranie aktualnie ustawionego menu, aby nim manipulować, z wyjątkiem onPrepareOptionMenu.

Rob W.

Odpowiedzi:


175

Opcja nr 1: Spróbuj invalidateOptionsMenu(). Nie wiem, czy to wymusi natychmiastowe odświeżenie paska akcji, czy nie.

Opcja nr 2: Sprawdź, czy getActionView()zwraca coś dla dotkniętego problemem MenuItem. Możliwe, że showAsActionpo prostu automatycznie tworzy dla Ciebie widoki akcji. Jeśli tak, prawdopodobnie możesz to włączyć / wyłączyć View.

Wydaje się, że nie mogę znaleźć sposobu na uzyskanie aktualnie ustawionego Menu, aby nim manipulować, z wyjątkiem onPrepareOptionMenu.

Możesz zawiesić się na przekazanym Menuprzedmiocie onCreateOptionsMenu(). Cytując dokumenty :

Możesz bezpiecznie trzymać się menu (i wszelkich utworzonych z niego elementów), wprowadzając w nim modyfikacje zgodnie z potrzebami, aż do następnego wywołania onCreateOptionsMenu ().


2
Wypróbowałem opcję nr 1 i to załatwiło sprawę. Ponieważ próbowałem zaktualizować interfejs użytkownika w wywołaniu zwrotnym z oddzielnego wątku, zgłaszał wyjątek, ponieważ w rzeczywistości nie byłem w wątku interfejsu użytkownika. Aby to naprawić, utworzyłem Handler i wysłałem wiadomość o odświeżeniu do programu obsługi, gdy wywołano moje wywołanie zwrotne. Ale ostatecznie użyłem getActivity (). InvalidateOptionsMenu (), aby odświeżyć menu.
brockoli

@brockoli: Ach, dobrze! Biorąc pod uwagę sformułowanie Javadoców dla tej metody, byłem sceptyczny, że przyniesie to pożądany efekt, chociaż wydawałoby się, że to był powód, dla którego dodali ją do API Level 11 w pierwszej kolejności. Miło słyszeć, że to działa dla Ciebie!
CommonsWare,

Uderzam głową w ścianę, próbując to rozgryźć i działa jak urok!
MinceMan

7
Jeśli korzystasz z biblioteki pomocy technicznej, użyj supportInvalidateOptionsMenu()zamiast niej
Tim Kist

2
@TimKist, supportInvalidateOptionsMenu()jest teraz przestarzałe; możesz bezpiecznie używać invalidateOptionsMenu().
Primož Kralj

12

w moim przypadku: invalidateOptionsMenupo prostu ponownie ustawiłem tekst na oryginalny, ale bezpośredni dostęp do pozycji menu i ponowne napisanie tekstu pożądania działało bez problemów:

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

ze względu na poniższy komentarz mogłem uzyskać dostęp do pozycji menu za pomocą następującego kodu:

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

W jaki sposób uzyskałeś uchwyt do widoku ActionBar z mnuTopMenuActionBar_?
Paul Mennega

1
kiedy pasek akcji zostaje zainicjowany, zapisałem widok w zmiennej składowej ... na przykład: @Override public boolean onCreateOptionsMenu (menu menu) {MenuInflater inflater = getMenuInflater (); inflater.inflate (R.menu.magazine_swipe_activity, menu); mnuTopMenuActionBar_ = menu; powrót prawda; }
cV2

Robiąc to, możesz mieć problemy z synchronizacją, prawda? Mam na myśli. nie wiesz DOKŁADNIE, kiedy onCreateOptionMenu będzie działać, więc możesz dotrzeć do swojego fragmentu kodu z mnuTopMenuActionBar_niezainicjowanym, prawda? Jak byś to obejść?
acrespo

hej, jeśli używany jest
pasek akcji

11

Aby odświeżyć menu z Fragmentu, wystarczy zadzwonić:

getActivity().invalidateOptionsMenu();

4

Użyłem tego kodu:

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

I zadziałało dla mnie jak urok, możesz znaleźć OnPrepareOptionsMenu tutaj


4
Jaki jest tutaj cel MenuInflater?
IgorGanapolsky

To jest genialne
Steve Kamau

2

Najpierw postępuj zgodnie z dwoma wierszami kodów, aby zaktualizować elementy paska działań, zanim ustawisz warunek w oncreateOptionMenu (). Na przykład:

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

1

Dla jasności pomyślałem, że bezpośredni przykład chwytania zasobu można przedstawić na podstawie poniższych, które moim zdaniem przyczyniają się do odpowiedzi na to pytanie za pomocą szybkiego bezpośredniego przykładu.

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

W takim przypadku przytrzymujesz odwołanie MenuItem na początku, a następnie zmieniasz jego stan (na przykład w przypadku zmian stanu ikon) w późniejszym określonym momencie.


-1

W Kotlin 1.2 po prostu zadzwoń:

invalidateOptionsMenu()

a onCreateOptionsMenufunkcja zostanie ponownie wywołana.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.