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.

misterbassman
fonte
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.

Kuffs
fonte
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;
}
Marco HC
fonte
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)
Matthew Blackford
fonte
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>
CONvid19
fonte
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).

Marius
fonte
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);

}
Parinda Rajapaksha
fonte
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);
    }
Spl2nky
fonte
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);
}
Harry Zhang
fonte
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);
}
Ezequiel García
fonte
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.

farid_z
fonte
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;
}
Suyog Gunjal
fonte
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);
}
AlexPad
fonte
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.

Filipe Brito
fonte
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);        
}
Jerry Frost
fonte
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.

Krishna Deepak
fonte
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).

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

}
pavel
fonte
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">
Lobo cinzento
fonte
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);
}
Ashana.Jackol
fonte