Jak dodać menu opcji do fragmentu w Androidzie

399

Próbuję dodać element do menu opcji z grupy fragmentów.

Utworzyłem nową MenuFragmentklasę i rozszerzyłem ją o fragmenty, w których chcę uwzględnić element menu. Oto kod:

Jawa:

public class MenuFragment extends Fragment {

    MenuItem fav;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
    }

    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        fav = menu.add("add");
        fav.setIcon(R.drawable.btn_star_big_off);
    }
}

Kotlin:

class MenuFragment : Fragment {

    lateinit var fav: MenuItem

    override fun onCreate(savedInstanceState: Bundle) {
        super.onCreate(savedInstanceState)
        setHasOptionsMenu(true)
    }

    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        fav = menu.add("add");
        fav.setIcon(R.drawable.btn_star_big_off);
    }
}

Z jakiegoś powodu onCreateOptionsMenuwydaje się, że nie działa.

misterbassman
źródło
może głupie pytanie ... naciskasz przycisk menu, prawda?
Ovidiu Latcu
2
..lol ... tak Nacisnąłem przycisk menu, próbowałem go również z: fav.setShowAsAction (MenuItem.SHOW_AS_ACTION_ALWAYS);
misterbassman
Cześć, może ten wątek ci pomoże lub sprawdzisz demo API pod działającym przykładem.
kameny

Odpowiedzi:

604

Wywołaj metodę super:

Jawa:

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        // TODO Add your menu entries here
        super.onCreateOptionsMenu(menu, inflater);
    }

Kotlin:

    override fun void onCreate(savedInstanceState: Bundle) {
        super.onCreate(savedInstanceState)
        setHasOptionsMenu(true)
    }

    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        // TODO Add your menu entries here
        super.onCreateOptionsMenu(menu, inflater)
    }

Umieść instrukcje dziennika w kodzie, aby sprawdzić, czy metoda nie jest wywoływana lub czy menu nie jest zmieniane przez kod.

Zapewniają również dzwonisz setHasOptionsMenu(boolean)w onCreate(Bundle)powiadomić fragment, który powinien uczestniczyć w obsłudze menu opcji.

Kuffs
źródło
2
Dzięki za pomoc, dodałem super metodę i zdałem sobie sprawę, że usunąłem @Override, więc dodałem to z powrotem, zaćmienie zgłosiło błąd, więc zastąpiłem MenuInflater, aby zaimportować android.view.MenuInflater; zamiast importu android.support.v4.view.MenuInflater; a teraz wszystko działa
misterbassman
183
nie wywoływanie setHasOptionsMenu (true) w fragmencie onCreate dostał mnie już dwa razy
joshkendrick
7
Przenosiłem moją aktywność do fragmentu i natknąłem się na ten problem. Podpis metody zmienił się z public boolean na public void, a argumenty również uległy zmianie. Pamiętaj o tym!
you786
14
Zauważ, że Fragment.onCreateOptionsMenu (Menu, MenuInflater) jest pustą metodą, więc wywołanie super nie jest wcale wymagane. Jedynym błędem tutaj była niewłaściwa sygnatura metody i prawdopodobnie brakujący setHasOptionsMenu () w onCreate ()
cmende
6
Zamień super.onCreateOptionsMenu na inflater.inflate (R.menu.menu_custom, menu);
Code_Worm,
197

Miałem ten sam problem, ale myślę, że lepiej podsumować i wprowadzić ostatni krok, aby go uruchomić:

  1. Dodaj metodę setHasOptionsMenu (true) do metody swojego fragmentu onCreate(Bundle savedInstanceState).

  2. Zastąp onCreateOptionsMenu(Menu menu, MenuInflater inflater)(jeśli chcesz zrobić coś innego w menu swojego Fragmentu) i onOptionsItemSelected(MenuItem item)metody w swoim Fragmentie.

  3. W onOptionsItemSelected(MenuItem item)metodzie działania upewnij się, że zwrócisz fałsz, gdy akcja elementu menu zostanie zaimplementowana w onOptionsItemSelected(MenuItem item)metodzie Fragmentu.

Przykład:

Czynność

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

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {

        case R.id.activity_menu_item:

            // Do Activity menu item stuff here
            return true;

        case R.id.fragment_menu_item:

            // Not implemented here
            return false;
        default:
            break;
    }

    return false;
}

Fragment

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
    ....
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    // Do something that differs the Activity's menu here
    super.onCreateOptionsMenu(menu, inflater);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {

        case R.id.activity_menu_item:

            // Not implemented here
            return false;
        case R.id.fragment_menu_item:

            // Do Fragment menu item stuff here
            return true;

        default:
            break;
    }

    return false;
}
Marco HC
źródło
2
Po prostu brakowało setHasOptionsMenu(true);Dzięki
Chad Bingham
1
W viewPager na niektórych urządzeniach menu jest wyświetlane dopiero za drugim razem, gdy przejdziesz do fragmentu
Roel
3
@Marco HC Twój kod działa poprawnie. Ale co, jeśli chcę ukryć część menu Aktywność lub Fragment? Wspomniałeś o tym, gdzie zaimplementować menu opcji (w działaniu i fragmencie). Ale co, jeśli chcę ukryć jakieś menu?
Shreyash Mahajan
@iDroidExplorer po prostu zachowaj odniesienie do tego elementu menu i ustaw widoczność na znikną lub niewidoczną. To twoje pytanie?
Marco HC
@ iDroidExplorer Próbowałem jego kodu i nie wiem jak, ale automatycznie ukrywa menu po przejściu na inne fragmenty.
Noor Ali Butt,
156

Jeśli okaże się, że onCreateOptionsMenu(Menu menu, MenuInflater inflater)metoda nie jest wywoływana, upewnij się, że wywołujesz następujące onCreate(Bundle savedInstanceState)metody z metody Fragment :

setHasOptionsMenu(true)
Matthew Blackford
źródło
To daje mi błąd jak NullPointerException
Pratik Butani,
2
Słuszna uwaga. Dzwoniłem do metody setHasOptionMenu ze statycznej metody newInstance. Ponieważ tylko dołączałem mój fragment, gdy parametr saveInstanceState miał wartość NULL, po zmianie konfiguracji ekranu menu nie zostanie utworzone. Metoda onCreate fragmentu jest poprawnym miejscem, w którym należy ustawić wartość setHasOptionMenu na wartość true.
argenkiwi
1
Używam Toolbari musiałem zadzwonić setHasOptionsMenu(true)w onCreateView()zamiast onCreate()zrobić to.
CLOUGH,
60

Jeśli potrzebujesz menuodświeżenia webviewwewnątrz określonego Fragment, możesz użyć:

Fragment :

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {

    // TODO Add your menu entries here
    inflater.inflate(R.menu.menu, menu);
    super.onCreateOptionsMenu(menu, inflater);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case R.id.exit:
        System.exit(1);
        break;

    case R.id.refresh:
        webView.reload();
        break;
    }
    return true;

}

menu.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/exit" android:title="Exit" android:icon="@drawable/ic_action_cancel" />
    <item android:id="@+id/refresh" android:title="Refresh" android:icon="@drawable/ic_action_refresh" />
</menu>
CONvid19
źródło
31

TL; DR

Użyj android.support.v7.widget.Toolbari po prostu zrób:

toolbar.inflateMenu(R.menu.my_menu)
toolbar.setOnMenuItemClickListener {
    onOptionsItemSelected(it)
}

Samodzielny pasek narzędzi

Większość sugerowanych rozwiązań, takich jak, setHasOptionsMenu(true)działa tylko wtedy, gdy działanie nadrzędne ma pasek narzędzi w swoim układzie i deklaruje je za pośrednictwem setSupportActionBar(). Następnie Fragmenty mogą uczestniczyć w populacji menu tego właśnie paska ActionBar :

Fragment.onCreateOptionsMenu (): Zainicjuj zawartość menu standardowych opcji hosta Fragment.

Jeśli chcesz mieć samodzielny pasek narzędzi i menu dla jednego określonego fragmentu , możesz wykonać następujące czynności:

menu_custom_fragment.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/menu_save"
        android:title="SAVE" />
</menu>

custom_fragment.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    ...

CustomFragment.kt

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    val view = inflater.inflate(layout.custom_fragment, container, false)
    val toolbar = view.findViewById<Toolbar>(R.id.toolbar)
    toolbar.inflateMenu(R.menu.menu_custom_fragment)
    toolbar.setOnMenuItemClickListener {
        onOptionsItemSelected(it)
    }
    return view
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    return when (item.itemId) {
        R.id.menu_save -> {
            // TODO: User clicked the save button
            true
        }
        else -> super.onOptionsItemSelected(item)
    }
}

Tak, to takie proste. Nie musisz nawet zastępować onCreate()lub onCreateOptionsMenu().

PS: Działa tylko z ( android.support.v4.app.Fragmenti android.support.v7.widget.Toolbarpamiętaj, aby użyć AppCompatActivityi AppCompatmotywu w twoim styles.xml).

Marius
źródło
1
bardzo mi pomogło
brahmy adigopula
23

W menu.xmlnależy dodać wszystkie elementy menu. Następnie możesz ukryć przedmioty, których nie chcesz widzieć przy pierwszym ładowaniu.

menu.xml

<item
    android:id="@+id/action_newItem"
    android:icon="@drawable/action_newItem"
    android:showAsAction="never"
    android:visible="false"
    android:title="@string/action_newItem"/>

Dodaj setHasOptionsMenu(true)metodę onCreate (), aby wywołać elementy menu w klasie Fragment.

FragmentClass.java

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
}

Nie musisz ponownie zastępować onCreateOptionsMenuw swojej klasie Fragmentów. Pozycje menu można zmienić (Dodaj / usuń), zastępując onPrepareOptionsMenumetodę dostępną we fragmencie.

@Override
public void onPrepareOptionsMenu(Menu menu) {
    menu.findItem(R.id.action_newItem).setVisible(true);
    super.onPrepareOptionsMenu(menu);

}
Parinda Rajapaksha
źródło
16

Musisz użyć menu.clear () przed napompowaniem menu.

@Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        menu.clear();
        inflater.inflate(R.menu.menu, menu);
        super.onCreateOptionsMenu(menu, inflater);
    }

i

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
    }
Spl2nky
źródło
1
Jest to poprawne, gdy chcesz mieć różne menu w różnych fragmentach i dodajesz fragmenty zamiast je zastępować.
Akshay Mahajan
Dziękuję Ci! menu.clear () pomóż mi usunąć opcję menu Aktywność.
kimcy929,
13

W moim przypadku oto kroki.

Krok 1

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Here notify the fragment that it should participate in options menu handling.
    setHasOptionsMenu(true);
}

Krok 2

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    // First clear current all the menu items
    menu.clear();

    // Add the new menu items
    inflater.inflate(R.menu.post_stuff, menu);

    super.onCreateOptionsMenu(menu, inflater);
}

Krok 3

 @Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.post_stuff:
            Log.d(TAG, "Will post the photo to server");
            return true;
        case R.id.cancel_post:
            Log.d(TAG, "Will cancel post the photo");
            return true;
        default:
            break;
    }
    return super.onOptionsItemSelected(item);
}
Harry Zhang
źródło
Miałem już menu dotyczące głównej aktywności, używając menu.clear()wyczyszczonego poprzedniego menu. Pracował dla mnie :)
Anbuselvan Rocky
8

Jeśli chcesz dodać własne menu

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.menu_custom, menu);
}
Ezequiel García
źródło
co jeśli jest widok zakładki i chcesz zawyżać różne menu dla każdego fragmentu?
Jainam Jhaveri
7

Miałem ten sam problem, moje fragmenty były stronami ViewPagera. Dzieje się tak dlatego, że podczas tworzenia FragmentPagerAdapter korzystałem z menedżera fragmentów potomnych, a nie z menedżera fragmentów obsługujących aktywność.

farid_z
źródło
3

Plik menu:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/play"
        android:titleCondensed="Speak"
        android:showAsAction="always"
        android:title="Speak"
        android:icon="@drawable/ic_play">
    </item>
    <item
        android:id="@+id/pause"
        android:titleCondensed="Stop"
        android:title="Stop"
        android:showAsAction="always"
        android:icon="@drawable/ic_pause">
    </item>
</menu>

Kod działania:

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

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {

        case R.id.play:
            Toast.makeText(getApplicationContext(), "speaking....", Toast.LENGTH_LONG).show();
            return false;

        case R.id.pause:
            Toast.makeText(getApplicationContext(), "stopping....", Toast.LENGTH_LONG).show();
            return false;

        default:
            break;
    }

    return false;
}

Kod fragmentu:

@Override

public void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {

        case R.id.play:
            text = page.getText().toString();
            speakOut(text);

            // Do Activity menu item stuff here
            return true;

        case R.id.pause:
            speakOf();

            // Not implemented here
            return true;

        default:
            break;
    }
    return false;
}
Suyog Gunjal
źródło
3

Twój kod jest w porządku. W metodzie brakowało tylko super:

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    // TODO add your menu : 
    inflater.inflate(R.menu.my_menu, menu);
    //TODO call super
    super.onCreateOptionsMenu(menu, inflater);
}
AlexPad
źródło
2

Oszalałem, ponieważ żadna z odpowiedzi tutaj nie zadziałała.

Aby wyświetlić menu musiałem zadzwonić: setSupportActionBar(toolbar)

Gotowy!

Uwaga: jeśli twój toolbarwidok nie jest w tym samym układzie aktywności, nie możesz użyć powyższego wywołania bezpośrednio z klasy aktywności, w takim przypadku musisz pobrać tę aktywność z klasy fragmentu, a następnie wywołać metodęsetSupportActionBar(toolbar) . Zapamiętywanie: twoja klasa aktywności powinna rozszerzać AppCompatActivity.

Mam nadzieję, że ta odpowiedź ci pomoże.

Filipe Brito
źródło
1

Ustawienie menu opcji po utworzeniu widoku fragmentu działało dla mnie dobrze.

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    setHasOptionsMenu(true);        
}
Jerry Frost
źródło
1

Mój problem był nieco inny. Zrobiłem wszystko dobrze. Ale odziedziczyłem niewłaściwą klasę dla działania hostującego fragment.

Dla jasności, jeśli przesłonisz onCreateOptionsMenu(Menu menu, MenuInflater inflater)fragment, upewnij się, że dziedziczy klasa aktywności, która obsługuje ten fragmentandroid.support.v7.app.ActionBarActivity (na wypadek, gdybyś chciał obsługiwać poniżej poziomu API 11).

Dziedziczyłem android.support.v4.app.FragmentActivitydo obsługi poziomu API poniżej 11.

Krishna Deepak
źródło
1

Dodam do tego jedną rzecz i powód, dla którego to nie działało.

Jest podobny do odpowiedzi Napstera.

  1. Upewnij się, że działalność hostingowa Twojego fragmentu się rozszerza AppCompatActivity, a nie FragmentActivity!

    public class MainActivity extends AppCompatActivity {
    
    }

    Z Dokumentacji Google dla FragmentActivity:

    Uwaga: Jeśli chcesz zaimplementować działanie, które zawiera pasek akcji, powinieneś zamiast tego użyć klasy ActionBarActivity, która jest podklasą tej klasy, dzięki czemu możesz używać interfejsów API Fragment na poziomie API 7 i wyższym.

  2. Aby zaktualizować odpowiedź Napstera - ActionBarActivityteraz jest przestarzała, użyj AppCompatActivityzamiast niej.

  3. Podczas używania AppCompatActivityupewnij się również, że ustawiłeś „motyw aktywności na Theme.AppCompatlub podobny motyw” (Dokument Google).

Uwaga: android.support.v7.app.AppCompatActivityjest podklasą android.support.v4.app.FragmentActivityklasy (patrz dokument referencyjny AppCompatActivity ).

Bastien
źródło
1

W folderze menu utwórz plik .menu xml i dodaj ten plik xml

<item
    android:id="@+id/action_search"
    android:icon="@android:drawable/ic_menu_search"
    android:title="@string/action_search"
    app:actionViewClass="android.support.v7.widget.SearchView"
    app:showAsAction="always|collapseActionView" />

W klasie fragmentów pomiń tę metodę i

implement SearchView.OnQueryTextListener    in your fragment class



@Override
 public void onViewCreated(View view, Bundle savedInstanceState) {    
  super.onViewCreated(view, savedInstanceState);
  setHasOptionsMenu(true);

}

Teraz po prostu ustaw plik XML menu w klasie fragmentów

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.menu_main, menu);

    final MenuItem item = menu.findItem(R.id.action_search);
    final SearchView searchView = (SearchView)    
    MenuItemCompat.getActionView(item);


    MenuItemCompat.setOnActionExpandListener(item,
            new MenuItemCompat.OnActionExpandListener() {
                @Override
                public boolean onMenuItemActionCollapse(MenuItem item) {
                    // Do something when collapsed

                    return true; // Return true to collapse action view
                }

                @Override
                public boolean onMenuItemActionExpand(MenuItem item) {
                    // Do something when expanded
                    return true; // Return true to expand action view
                }
            });

}
pavel
źródło
0

Jeśli wszystkie powyższe funkcje nie działają, musisz debugować i upewnić się, że funkcja onCreateOptionsMenu została wywołana (poprzez umieszczenie dziennika debugowania lub zapisu ...)

Jeśli nie jest uruchomiony, być może motyw Androida nie obsługuje paska akcji. Otwórz plik AndroidManifest.xml i ustaw wartość dla android:themepaska akcji obsługi motywów :

 <activity
     android:name=".MainActivity"
     android:label="@string/app_name"
     android:theme="@style/Theme.AppCompat">
Szary Wilk
źródło
0

na onCreate metody Add setHasOptionMenu ()

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
}

Następnie zastąp swoje menu onCreateOptionsMenu

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    menu.add("Menu item")
            .setIcon(android.R.drawable.ic_delete)
            .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
}
Ashana.Jackol
źródło