Como adicionar o menu Opções ao fragmento no Android


399

Estou tentando adicionar um item ao menu de opções de um grupo de fragmentos.

Eu criei uma nova MenuFragmentclasse e estendi isso para os fragmentos nos quais desejo incluir o item de menu. Aqui está o código:

Java:

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

Por algum motivo, o onCreateOptionsMenuparece não funcionar.


talvez uma pergunta boba ... você pressiona o botão de menu certo?
— Ovidiu Latcu 29/11

2
..lol ... sim, eu pressionei o botão de menu, também tentei com e sem: fav.setShowAsAction (MenuItem.SHOW_AS_ACTION_ALWAYS);
— misterbassman

Oi, talvez este tópico o ajude ou verifique a demonstração da API para obter um exemplo de trabalho.
— Kameny

Respostas:


605

Chame o super método:

Java:

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

Coloque instruções de log no código para ver se o método não está sendo chamado ou se o menu não está sendo alterado pelo seu código.

Também garantir que você está chamando setHasOptionsMenu(boolean)em onCreate(Bundle)notificar o fragmento que deveria participar na manipulação menu de opções.


2
Obrigado pela ajuda, eu adicionei o super método e percebi que havia removido o @Override e o adicionei novamente, o eclipse gerou um erro e substituí o MenuInflater para importar android.view.MenuInflater; em vez de importar android.support.v4.view.MenuInflater; e agora tudo está funcionando
— misterbassman

183
não chamar setHasOptionsMenu (true) no onCreate do Fragmento ficou-me duas vezes agora
— joshkendrick

7
Eu estava transferindo minha atividade para um fragmento e me deparei com esse problema. A assinatura do método foi alterada de public boolean para public void e os argumentos também foram alterados. Certifique-se de tomar nota disso!
— you786

14
Observe que Fragment.onCreateOptionsMenu (Menu, MenuInflater) é um método vazio, portanto, chamar super não é necessário. O único erro aqui foi a assinatura errada método e, possivelmente, um setHasOptionsMenu falta () em onCreate ()
— cmende

6
Substitua super.onCreateOptionsMenu por inflater.inflate (R.menu.menu_custom, menu);
— Code_Worm

197

Eu tive o mesmo problema, mas acho melhor resumir e apresentar a última etapa para fazê-lo funcionar:

  1. Adicione o método setHasOptionsMenu (true) ao método do seu fragmento onCreate(Bundle savedInstanceState).

  2. Substituir onCreateOptionsMenu(Menu menu, MenuInflater inflater)(se você quiser fazer algo diferente no menu do seu Fragmento) e onOptionsItemSelected(MenuItem item)métodos no seu Fragmento.

  3. Dentro onOptionsItemSelected(MenuItem item)do método da sua atividade, certifique-se de retornar falso quando a ação do item de menu for implementada no onOptionsItemSelected(MenuItem item)método do fragmento.

Um exemplo:

Atividade

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

Fragmento

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

2
Só estava faltando setHasOptionsMenu(true);Graças
— Chad Bingham

11
Em um viewPager em alguns dispositivos do menu só é mostrado pela segunda vez o que você vá para o fragmento
— Roel

3
@ Marco HC, seu código funciona bem. Mas e se eu quiser ocultar alguns dos menus de Atividade ou Fragmento? Você mencionou sobre onde implementar qual menu de opções (Em atividade e fragmento). Mas e se eu quiser esconder algum menu?
— Shreyash Mahajan

O @iDroidExplorer apenas mantém uma referência a esse MenuItem e define a visibilidade como oculta ou invisível. Essa é a sua pergunta?
— Marco HC

@iDroidExplorer Tentei o código dele e não sei como, mas ele oculta automaticamente o menu quando alterno para outros fragmentos.
— Noor Ali Butt

156

Se você achar que o onCreateOptionsMenu(Menu menu, MenuInflater inflater)método não está sendo chamado, chame o seguinte no onCreate(Bundle savedInstanceState)método do Fragment :

setHasOptionsMenu(true)

Isso me dá erro como NullPointerException
— Pratik Butani

2
Bom ponto. Eu estava chamando o método setHasOptionMenu do método estático newInstance. Como eu estava apenas anexando meu fragmento quando o SaveInstanceState era nulo, quando a configuração da tela mudou, o menu não seria criado. O método onCreate do fragmento é o local correto onde definir setHasOptionMenu como true.
— Argenkiwi

11
Eu estou usando um Toolbare tive que chamar setHasOptionsMenu(true)em onCreateView()vez onCreate()de fazê-lo.
— CLOUGH

60

Se você precisar menuatualizar um webviewdentro de um específico Fragment, poderá usar:

Fragmento :

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>

31

TL; DR

Use o android.support.v7.widget.Toolbare apenas faça:

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

Barra de ferramentas autônoma

A maioria das soluções sugeridas, como, setHasOptionsMenu(true)está funcionando apenas quando a Atividade pai tem a Barra de Ferramentas em seu layout e a declara via setSupportActionBar(). Em seguida, os fragmentos podem participar da população de menus dessa ActionBar exata :

Fragment.onCreateOptionsMenu (): inicialize o conteúdo do menu de opções padrão do host do Fragment.

Se você deseja uma barra de ferramentas e menu independentes para um fragmento específico, faça o seguinte:

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

Sim, é assim tão fácil. Você nem precisa substituir onCreate()ou onCreateOptionsMenu().

PS: Isso está funcionando apenas com android.support.v4.app.Fragmente android.support.v7.widget.Toolbar(também certifique-se de usar AppCompatActivitye um AppCompattema no seu styles.xml).


11
realmente ajudou muito para mim
— brahmy adigopula

23

No menu.xmlvocê deve adicionar todos os itens de menu. Em seguida, você pode ocultar itens que não deseja ver no carregamento inicial.

menu.xml

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

Adicione setHasOptionsMenu(true)o método onCreate () para chamar os itens de menu na sua classe Fragment.

FragmentClass.java

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

Você não precisa substituir onCreateOptionsMenusua classe Fragment novamente. Os itens de menu podem ser alterados (Adicionar / remover) substituindo o onPrepareOptionsMenumétodo disponível no Fragmento.

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

}

16

Você precisa usar menu.clear () antes de inflar os menus.

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

e

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

11
Isso está correto quando você deseja menus diferentes em fragmentos diferentes e está adicionando fragmentos em vez de substituí-los.
— Akshay Mahajan

Obrigado! menu.clear () me ajuda a remover a opção de menu Atividade.
— kimcy929

13

No meu caso, aqui estão os passos.

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

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

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

Eu já tinha menu na atividade principal, usando o menu.clear()menu anterior limpo. Trabalhou para mim :)
— Anbuselvan Rocky

8

Se você deseja adicionar seu menu personalizado

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

e se houver uma exibição de guia e você desejar aumentar os menus diferentes para cada fragmento?
— Jainam Jhaveri

7

Eu tive o mesmo problema, meus fragmentos eram páginas de um ViewPager. A razão pela qual isso estava acontecendo é que eu estava usando o gerenciador de fragmentos filho, em vez do gerenciador de fragmentos de suporte a atividades ao instanciar FragmentPagerAdapter.


3

Arquivo de 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>

Código da atividade:

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

Código do fragmento:

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

3

Seu código está bom. Apenas o super estava faltando no método:

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

2

Eu estava ficando louco porque nenhuma das respostas aqui funcionou para mim.

Para mostrar o menu, tive que ligar: setSupportActionBar(toolbar)

Feito!

Nota: se sua toolbarvisualização não estiver no mesmo layout de atividade, você não poderá usar a chamada acima diretamente da sua classe de atividade. Nesse caso, será necessário obter essa atividade da sua classe de fragmento e chamar o setSupportActionBar(toolbar). Lembrando: sua classe de atividade deve estender a AppCompatActivity.

Espero que esta resposta o ajude.


1

Definir o menu de opções após criar a exibição de fragmento funcionou bem para mim.

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

1

Meu problema era um pouco diferente. Eu fiz tudo certo. Mas estava herdando a classe errada para a atividade que hospedava o fragmento.

Portanto, para ficar claro, se você estiver substituindo onCreateOptionsMenu(Menu menu, MenuInflater inflater)o fragmento, verifique se a classe de atividade que hospeda esse fragmento é herdada android.support.v7.app.ActionBarActivity(caso você queira oferecer suporte abaixo do nível 11 da API).

Eu estava herdando o android.support.v4.app.FragmentActivitynível da API de suporte abaixo de 11.


1

Uma coisa que eu acrescentaria a isso e a razão de não estar funcionando para mim.

É semelhante à resposta do Napster.

  1. Verifique se a atividade de hospedagem do seu fragmento se estende AppCompatActivity, não FragmentActivity!

    public class MainActivity extends AppCompatActivity {
    
    }

    Na documentação de referência do Google para FragmentActivity:

    Nota: Se você deseja implementar uma atividade que inclui uma barra de ação, use a classe ActionBarActivity, que é uma subclasse desta, para que você possa usar APIs de Fragmento na API nível 7 e superior.

  2. Para atualizar a resposta do Napster - ActionBarActivityagora sendo preterida, use em seu AppCompatActivitylugar.

  3. Ao usar AppCompatActivity, também defina "o tema da atividade como Theme.AppCompatou um tema semelhante" (Google Doc).

Nota: android.support.v7.app.AppCompatActivityé uma subclasse da android.support.v4.app.FragmentActivityclasse (consulte AppCompatActivity ref doc).


1

Na pasta do menu, crie um arquivo .menu xml e adicione este 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" />

Na sua classe de fragmento, substitua esse método e

implement SearchView.OnQueryTextListener    in your fragment class



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

}

Agora basta configurar o arquivo xml do menu na classe de fragmento

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

}

0

Se todas as opções acima não funcionarem, é necessário depurar e certificar-se de que a função onCreateOptionsMenu tenha sido chamada (colocando o registro de depuração ou gravação ...)

Se não for executado, talvez o seu tema Android não seja compatível com a barra de ação. Abra AndroidManifest.xml e defina o valor para android:themecom a barra de ação de suporte ao tema :

 <activity
     android:name=".MainActivity"
     android:label="@string/app_name"
     android:theme="@style/Theme.AppCompat">

0

no seu método onCreate , adicione setHasOptionMenu ()

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

Em seguida, substitua seu 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);
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.