Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android actionbar submenu items displayed on top of the actionbar instead of below the bar

I need to show the submenu below the bar, not on top of the bar itself.

Copying my actionbar xml below

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

In the activity (App also has a navigation drawer)

public boolean onCreateOptionsMenu(Menu menu) {
    if (!mNavigationDrawerFragment.isDrawerOpen()) {
        getMenuInflater().inflate(R.menu.main, menu);
        restoreActionBar();
        return true;
    }
    return super.onCreateOptionsMenu(menu);
}
like image 780
BholaBakra Avatar asked Dec 08 '14 07:12

BholaBakra


2 Answers

Simply.

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

like image 194
Châu Nguyễn Avatar answered Oct 21 '22 12:10

Châu Nguyễn


Preamble

As usual, I faced a strange problem while developing an Android app, tried to find a solution and landed to this question. As it was in many cases before, there is no an answer. So I was compelled to solve the problem from scratch and now posting the answer with my workaround.

Input

I have an Android app with action bar and some menu items, which have to be extended with dropdown submenu. First attempt was to implement it as suggested by Android documentation. So I added new menu item menu_sort into existing action bar menu and sub-menu container into it:

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

Result

The effect was exactly as described in the question: the submenu is displayed on top of the action bar. Here is the screenshot taken on Android 5.1.1:

problem with dropdown submenu on top of its parent action bar

I played with many options and code snippets - nothing helped. Finally I came to the following

Solution

First, move all the submenu into a separate menu layout, say, menu/sorting.xml, and remove it from menu_sort item of the main menu (shown above).

Second, modify or create onPrepareOptionsMenu event handler with the following code:

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

Here is the result:

properly positioned dropdown submenu under action bar - workaround

Now the dropdown is displayed as expected from very beginning.

like image 26
Stan Avatar answered Oct 21 '22 11:10

Stan