Android PopupMenu : Show floating menu anchored to a view
PopupMenu
shows floating Menu in a popup window anchored to a view. PopupMenu was added with API level 11
. PopupMenu itself decides its position on screen around anchor view based upon available space. If there is room below anchor view, it will show below it. Otherwise it will be shown above anchor view.
PopupMenu provides two interfaces to handler dismiss and item click.
1. PopupMenu.OnDismissListener
Callback interface used to notify the application that popup menu has been closed.
2. PopupMenu.OnMenuItemClickListener
Interface responsible for receiving menu item click events if the items themselves do not have individual item click listeners.
Sample PopupMenu Application
Our main target is to achieve above output. Activity layout will have two buttons one each aligned to top and bottom of view. PopupMenu will be shown on clicking buttons. In screenshot, PopupMenu is shown above it for anchor view in bottom and it is shown below anchor view for top aligned button.
Second target is to acheive styling of PopupMenu. We will define style for text appearance and background of PopupMenu as by deafult it will have style inherited from android:Widget.Holo.Light.ListPopupWindow.
Let’s start making changes with /res/layout/activity_main.xml
. Final xml will be similar to as below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.andoidsrc.popupmenu.MainActivity" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:onClick="onClick" android:text="Click to show PopupMenu" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:onClick="onClick" android:text="Click to show PopupMenu" /> </RelativeLayout> |
We need to create a menu layout to be inflated in PopupMenu. Create /res/menu/popup_menu.xml
as below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" tools:context="com.andoidsrc.popupmenu.MainActivity" > <item android:id="@+id/lang_java" android:showAsAction="ifRoom|withText" android:title="Java" android:visible="true"/> <item android:id="@+id/lang_android" android:showAsAction="ifRoom|withText" android:title="Android" android:visible="true"/> <item android:id="@+id/lang_ruby" android:showAsAction="ifRoom|withText" android:title="Ruby" android:visible="true"/> <item android:id="@+id/lang_python" android:showAsAction="ifRoom|withText" android:title="Python" android:visible="true"/> </menu> |
For styling PopupMenu,add below lines to /res/values/styles.xml
. It is assumed that Application theme is set to android:theme="@style/AppTheme"
in manifest file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<!-- Application theme. --> <style name="AppTheme" parent="AppBaseTheme"> <!-- All customizations that are NOT specific to a particular API-level can go here. --> <item name="android:popupMenuStyle">@style/AndroidSRC.PopupMenu</item> <item name="android:itemTextAppearance">@style/AndroidSRC.TextAppearance</item> </style> <style name="AndroidSRC.PopupMenu" parent="android:Widget.Holo.Light.ListPopupWindow"> <item name="android:popupBackground">#21B6A8</item> </style> <style name="AndroidSRC.TextAppearance" parent="@android:style/Widget.Holo.Light.TextView"> <item name="android:textColor">@android:color/white</item> <item name="android:textStyle">bold</item> </style> |
Finally, Let add code for PopupMenu in MainActivity.java
. Activity will implement View.OnClickListener
for listening to onClick events for buttons. In onClick(), We will create a PopupMenu object. View will be set with inflate(int resourceId)
. Attach OnDismissListener
and OnMenuItemClickListener
in order to listen for menu dismiss and handling for menu click events.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
package com.andoidsrc.popupmenu; import android.app.Activity; import android.os.Bundle; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.PopupMenu; import android.widget.Toast; public class MainActivity extends Activity implements OnClickListener { private PopupMenu popupMenu; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public void onClick(View anchor) { // TODO Auto-generated method stub popupMenu = new PopupMenu(MainActivity.this, anchor); popupMenu.setOnDismissListener(new OnDismissListener()); popupMenu.setOnMenuItemClickListener(new OnMenuItemClickListener()); popupMenu.inflate(R.menu.popup_menu); popupMenu.show(); } private class OnDismissListener implements PopupMenu.OnDismissListener { @Override public void onDismiss(PopupMenu menu) { // TODO Auto-generated method stub Toast.makeText(getApplicationContext(), "Popup Menu is dismissed", Toast.LENGTH_SHORT).show(); } } private class OnMenuItemClickListener implements PopupMenu.OnMenuItemClickListener { @Override public boolean onMenuItemClick(MenuItem item) { // TODO Auto-generated method stub switch (item.getItemId()) { case R.id.lang_java: Toast.makeText(getApplicationContext(), "Java got clicked", Toast.LENGTH_SHORT).show(); return true; case R.id.lang_android: Toast.makeText(getApplicationContext(), "Android got clicked", Toast.LENGTH_SHORT).show(); return true; case R.id.lang_python: Toast.makeText(getApplicationContext(), "Python got clicked", Toast.LENGTH_SHORT).show(); return true; case R.id.lang_ruby: Toast.makeText(getApplicationContext(), "Ruby got clicked", Toast.LENGTH_SHORT).show(); return true; } return false; } } } |