2014-12-08 21 views
5

Devo mostrare il sottomenu sotto la barra, non in cima alla barra stessa.Elementi del sottomenu della barra delle azioni di Android visualizzati nella parte superiore della barra delle azioni anziché sotto la barra

Copia mia ActionBar xml sotto

<menu xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity"> 
    <item 
     android:id="@+id/action_pages" 
     android:orderInCategory="1" 
     android:showAsAction="withText|always" 
     android:icon="@drawable/ic_action_pages" 
     android:title=""> 
     <menu> 
      <item android:id="@+id/item1" android:title="Placeholder"></item> 
     </menu> 
    </item> 
</menu> 

Nell'attività (applicazione ha anche un cassetto di navigazione)

public boolean onCreateOptionsMenu(Menu menu) { 
    if (!mNavigationDrawerFragment.isDrawerOpen()) { 
     getMenuInflater().inflate(R.menu.main, menu); 
     restoreActionBar(); 
     return true; 
    } 
    return super.onCreateOptionsMenu(menu); 
} 
+0

capito? – JackyBoi

+0

Lo stesso problema è qui (Android 5.1). Dopo diversi anni di inciampare su tali "caratteristiche" qua e là durante lo sviluppo per Android, devo dire che Android è una piattaforma molto frustrante, ahimè. – Stan

risposta

1

Preambolo

Come al solito, ho dovuto affrontare un problema strano, mentre lo sviluppo di un'app per Android, ho cercato di trovare una soluzione e sono arrivato a questa domanda. Come in molti casi prima, non c'è una risposta. Così sono stato costretto a risolvere il problema da zero e ora postando la risposta con la mia soluzione alternativa.

ingresso

Ho un app Android con barra di azione e di alcune voci di menu, che devono essere esteso con sottomenu a tendina. Il primo tentativo è stato implementarlo come suggerito dalla documentazione di Android. Così ho aggiunto nuova voce di menu menu_sort in esistente menù barra delle azioni e sub menu contenitore in esso:

<menu xmlns:android="http://schemas.android.com/apk/res/android" > 
    <item android:id="@+id/id1" android:icon="@drawable/ic_1" 
     android:title="@string/id1" android:showAsAction="withText|always"/> 
    ... 

    <item 
    android:id="@+id/menu_sort" 
    android:icon="@drawable/ic_menu_sort_selector" 
    android:title="&#x25BE;" 
    android:titleCondensed="&#x25BE;" 
    android:showAsAction="withText|always"> 
    <menu> 
     <item 
      android:id="@+id/menu_sort_by_name" 
      android:showAsAction="never" 
      android:checkable="true" 
      android:checked="true" 
      android:title="@string/sort_by_name"/> 
     <item 
      android:id="@+id/menu_sort_by_priority" 
      android:showAsAction="never" 
      android:checkable="true" 
      android:checked="false" 
      android:title="@string/sort_by_priority"/> 
     <item 
      android:id="@+id/menu_sort_by_memory" 
      android:showAsAction="never" 
      android:checkable="true" 
      android:checked="false" 
      android:title="@string/sort_by_memory"/> 
    </menu> 
    </item> 
</menu> 

Risultato

L'effetto è stato esattamente come descritto nella domanda: il sottomenu viene visualizzato sulla parte superiore della barra delle azioni. Ecco lo screenshot preso su Android 5.1.1:

problem with dropdown submenu on top of its parent action bar

ho giocato con molte opzioni e frammenti di codice - non serviva a niente. Finalmente sono giunto alla seguente

Soluzione

In primo luogo, spostare tutto il sottomenu in un layout menu separato, per esempio, menu/sorting.xml, e rimuoverla dalla menu_sort voce del menù principale (mostrato sopra).

In secondo luogo, modificare o creare onPrepareOptionsMenu gestore di eventi con il seguente codice:

@Override 
public boolean onPrepareOptionsMenu(Menu menu) 
{ 
    // as solution utilizes PopupMenu, 
    // take care about older Android versions if necessry 
    // if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) 

    // here goes most crazy part: we use menu id 
    // to retrieve corresponding view, automatically created by OS; 
    // imho, this is a hack, and menu item should have getView() method or similar; 
    View menuItemView = findViewById(R.id.menu_sort); 

    // by the way, menuItemView could probably be null under some circumstances 

    // create a popup anchored to the view (menu item) 
    final PopupMenu popupMenu = new PopupMenu(this, menuItemView); 
    // API 14 
    // popupMenu.inflate(R.menu.sorting); 
    // API 11 (HONEYCOMB) 
    popupMenu.getMenuInflater().inflate(R.menu.sorting, popupMenu.getMenu()); 

    // process popup clicks as appropriate 
    popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() 
    { 
    @Override 
    public boolean onMenuItemClick(MenuItem item) 
    { 
     switch(item.getItemId()) 
     { 
     // ... place some code 
     } 
     return true; 
    } 
    }); 

    // bind the popup to the item menu 
    menu.findItem(R.id.menu_sort).setOnMenuItemClickListener(new OnMenuItemClickListener() 
    { 
    @Override 
    public boolean onMenuItemClick(MenuItem item) 
    { 
     popupMenu.show(); 
     return true; 
    } 
    }); 

    return super.onPrepareOptionsMenu(menu); 
} 

Ecco il risultato:

properly positioned dropdown submenu under action bar - workaround

Ora la discesa viene visualizzato come previsto dal principio.

+0

è meglio usare listener in onOptionsItemSelected invece onPrepareOptionsMenu – JFouad

+0

@JFouad, non sono sicuro che tu capisca il problema. Il tuo suggerimento è irrilevante, per non dire sbagliato. – Stan

+0

è meglio per spostare questo codice ' menu.findItem (R.id.menu_sort) .setOnMenuItemClickListener (nuova OnMenuItemClickListener() { @Override onMenuItemClick public boolean (MenuItem articolo) { popupMenu.show(); return true; } }); ' da onPrepareOptionsMenu a onOptionsItemSelected – JFouad

3

Semplicemente.

<style name="AppTheme" parent="AppBaseTheme"> 
    <item name="actionOverflowMenuStyle">@style/OverflowMenu</item> 
</style> 

<style name="OverflowMenu" parent="Widget.AppCompat.PopupMenu.Overflow"> 
    <!-- Required for pre-Lollipop. --> 
    <item name="overlapAnchor">false</item> 

    <!-- Required for Lollipop. --> 
    <item name="android:overlapAnchor">false</item> 
</style> 

+0

Questo ha funzionato alla grande, grazie! android: overlapAnchor non è supportato a livello di API 15 (che sto prendendo di mira), quindi ho dovuto inserire questo XML nel mio file res/values-v21/styles.xml, e quindi ho rimosso l'impostazione android: overlapAnchor per il mio normale res/values ​​/ styles.xml. Questo ha eliminato gli errori e gli avvertimenti e ora funziona alla grande! – HanClinto

0

@ soluzione di Stan non funziona per me, ecco il mio modo per implementare sotto-menu in cima ActionBar (ma al di sotto del menu principale, naturalmente):
I Ho creato 2 file xml: menu_main.xml e menu_more.xml si trova nella directory res/menu di


Il primo 'menu_main.xml' contengono il menu:

<menu 
xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:app="http://schemas.android.com/apk/res-auto"> 

<!-- our addMenu doesn't have sub-items--> 
<item 
    android:id="@+id/action_add" 
    android:icon="@drawable/ic_note_add_white_24dp" 
    android:title="@string/action_add" 
    app:showAsAction="ifRoom"/> 

<!-- our moreMenu which show drop-down menu when clicked--> 
<item 
    android:id="@+id/action_more" 
    android:icon="@drawable/ic_more_vert_white_24dp" 
    android:title="@string/action_more" <!--in text: "more"--> 
    app:showAsAction="always"/> 

</menu> 


e la seconda 'menu_more.xml 'contenere il menu a discesa:

<menu xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:app="http://schemas.android.com/apk/res-auto"> 

<!-- This menu will be hidden by default--> 
<!-- But will be visible when moreMenu with '@+id/action_more' is clicked--> 
<item 
    android:id="@+id/action_settings" 
    app:showAsAction="ifRoom|withText" 
    android:title="@string/action_settings" <!-- In text: "Settings"--> 
    android:visible="true"/> 

</menu> 


Ecco cosa mi precedente nus simile:
result-after-add-2-xmls (non ho abbastanza 10 reputazione per visualizzare l'immagine)
Nell'attività, ho sovrascritto questo metodo:

booleano onPrepareOptionsMenu (menu Menu) pubblica


Nel metodo precedente, ottengo riferimento al menu principaleItem (in questo caso è il menu con @ + id/action_more situato in m enu_main.xml file), quindi impostare setOnMenuItemClickListener su di esso e, infine, dichiarare e impostare un PopupMenu esempio per gestire e voci del menu di visualizzazione:

// show popup menu when menuMore clicked 
menu.findItem(R.id.action_more).setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() 
{ 
    @Override 
    public boolean onMenuItemClick(MenuItem item) 
    { 
     // get reference to menuMore item 
     View menuMore = findViewById(item.getItemId()); 
     // create a popup anchored to the view (menuMore) 
     // notes: if declare and set up PopupMenu Outside of this onMenuItemClick() 
     // then it'll not work! 
     // Because: the view you put into PopupMenu() could be null 
     final PopupMenu popupMenu = new PopupMenu(getApplicationContext(), menuMore); 
     // inflate 'menu_more.xml' layout file 
     // which contain all sub-items of menu 
     popupMenu.getMenuInflater().inflate(R.menu.menu_more, popupMenu.getMenu()); 

     // process popup clicks on sub-items 
     popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() 
     { 
      @Override 
      public boolean onMenuItemClick(MenuItem item) 
      { 
       switch(item.getItemId()){ 
        case R.id.action_settings: 
         Toast.makeText(getApplicationContext(), "showing SettingsActivity..", 
           Toast.LENGTH_SHORT).show(); 
         break; 
        // more items go here 
       } 
       return true; 
      } 
     }); 

     popupMenu.show(); 
     return true; 
    } 
}); 

return super.onPrepareOptionsMenu(menu); 


Ed ecco il risultato finale:
final-look-drop-down-menu

Problemi correlati