Okay, so I have a dynamic menu (In my navigation drawer), generated like so:
In my Main.java onCreate():
DatabaseManager databaseAccess = DatabaseManager.getInstance(this);
databaseAccess.open();
List<String> folders = databaseAccess.getFolders();
databaseAccess.close();
// Set up the menu items
setupMenu(folders);
This gets the headings into an array called 'folders', then runs the setupMenu function:
private void setupMenu(List<String> folders) {
// Sets up the menu
Log.i("Folder Size",String.valueOf(folders.size()));
NavigationView navView = findViewById(R.id.nav_view);
Menu menu = navView.getMenu();
int x = 0;
while(x < folders.size()) {
menu.add(R.id.myfolders,Menu.NONE,Menu.NONE,folders.get(x++));
}
navView.invalidate();
}
Which adds it to the id:myfolders in activity_main_drawer:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:showIn="navigation_view">
<item android:title="My Folders"
android:orderInCategory="1"
android:id="#+id/myfolders">
<menu></menu>
</item>
<item android:checkableBehavior="single" android:orderInCategory="2">
<menu android:id="#+id/about_menu">
<item android:id="#+id/system_about"
android:title="About"
android:icon="#drawable/ic_info" />
</menu>
</item>
</menu>
This all works perfectly, however I want to add longpress functionality to my menu items. I have no idea how to go about doing this, can anyone help?
You get a MenuItem from menu.add() then you can call:
menuItem.getActionView().setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
return false; // true
}
});
But not before you set action view: menuItem.setActionView(new ImageButton(this)).
I'm building an app with AndroidStudio.
I have a problem with my Menu.
This is my menu file .xml:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="#+id/action_settings"
android:orderInCategory="100"
android:title="#string/action_settings"/>
<item
android:id="#+id/action_logout"
android:orderInCategory="100"
android:title="Logout"/>
</menu>
This is that I can see from Preview:
In my activity main, I have this code to create this menu:
public class MainActivity extends Activity {
public MyDatabase db;
public ProgressDialog dialog;
public String url="";
private static final Intent SCAN_INTENT = new Intent("com.google.zxing.client.android.SCAN");
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#SuppressLint("RestrictedApi")
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.care_home, menu);
if (menu != null) {
}
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
return super.onOptionsItemSelected(item);
}
}
But if I try to start my application I can see this:
As you can see, I can't see icon of application and I can't see Option menu.
How can I do this?
You may use lower version android device for that press hardware menu button of device it will shows your menu.My suggestion is to test it on at least above on jelly bean .
Extend AppCompatActivity not Activity. and create menu like below:
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.care_home, menu);
return return super.onCreateOptionsMenu(menu);;
}
and care_home.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/action_settings"
android:orderInCategory="100"
android:title="#string/action_settings"
app:showAsAction="always" />
<item
android:id="#+id/action_logout"
android:orderInCategory="100"
android:title="Logout"
app:showAsAction="always" />
For setting AppBar you can read Here.
you are extending Activity only that's why you are unable to see the toolbar or action.
public class MainActivity extends Activity {}
instead use this :
public class MainActivity extends AppCompatActivity{
For more please read the android documentation about appBars:
Android Docs
First extend your activity with AppCompatActivity rather Activity like:
public class MainActivity extends AppCompatActivity{
And return return (super.onCreateOptionsMenu(menu)); it rather true like:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.care_home, menu);
if (menu != null) {
}
return (super.onCreateOptionsMenu(menu));
}
I want to show a icon button the right side of my actionbar.
This is my menu_drawing XML
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".DrawingActivity">
<item android:id="#+id/action_search"
android:icon="#drawable/ic_delete_white_36dp"
android:title="tick"
android:orderInCategory="0"
app:showAsAction="always" />
</menu>
This is my activity
public class pollActivity extends Activity {
Button SEND;
Button CANCEL;
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_drawing, menu);
return super.onCreateOptionsMenu(menu);
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.poll_layout);
}
}
This is my style
<style name="MyActionBarTheme" parent="android:Widget.Material.Light.ActionBar">
<item name="android:background">#255e7c</item>
<item name="android:titleTextStyle">#style/TitleBarTextColor</item>
<item name="android:homeAsUpIndicator">#mipmap/backbtn</item>
</style>
What is the problem? The icon is not showing and only title appear as "word" on my overflow button?
Background
I have a menu item in the action bar (toolbar actually) that when clicked, shows a list of items to choose from, similar to radio-buttons:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:icon="#drawable/..."
android:title="#string/..."
app:showAsAction="always">
<menu>
<group
android:id="#+id/..."
android:checkableBehavior="single">
<item .../>
<item .../>
<item .../>
</group>
</menu>
</item>
</menu>
I need to put an item below this list of items, that will have a divider between it and the list. Similar to what the material design guidelines show (taken from here) :
EDIT: here's a sketch of what I want to do:
The problem
I can't find a way to do it.
What I've tried
The only possible solutions I've found are:
change the theme of the activity (here), but this will also affect other menu items of the activity
methods to put a divider between menu items when they appear on the action bar, but here they do not appear on the toolbar itself. They appear on a popup menu of a selected item.
I tried to put fake items between the list and the extra item, and I also tried to put a group, an empty group and even tried various attributes.
Sadly nothing worked.
The question
How can I add a divider between specific items of an action-item's popup menu ?
Perhaps I need to create a custom popup menu when clicking on the action item (like here) ? If so, how do I put a divider between specific items there ?
Maybe use a Spinner as an action item?
You should use action layout
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".LandingActivity">
<item
android:id="#+id/action_cart"
android:title="cart"
android:actionLayout="#layout/cart_update_count"
android:icon="#drawable/shape_notification"
app:showAsAction="always"/>
</menu>
and then the action layout can have the textview with divider.
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical">
<View
android:id="#+id/divider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/divider"/>
<TextView
android:id="#android:id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical"
android:textAppearance="?attr/textAppearanceListItemSmall"/>
</LinearLayout>
then you can add the click listener in code
As of SDK version 28, you can use menu.setGroupDividerEnabled(boolean). If you're using ContextMenu this is only supported on SDK 28+, but MenuCompat offers backwards compatibility when used in onCreateOptionsMenu().
This will add a divider between the actions for each different groupId, shown as 0 and 1 below:
menu.add(0, getAdapterPosition(), action1, R.string.action1);
menu.add(1, getAdapterPosition(), action2, R.string.action2);
menu.setGroupDividerEnabled(true);
// Or for MenuCompat < SDK 28:
MenuCompat.setGroupDividerEnabled(menu, true);
Documentation here: https://developer.android.com/reference/android/view/Menu#setGroupDividerEnabled(boolean)
EDIT: Sample code as requested by asker:
Here's the code I am currently using in my app, located in a RecyclerView Adapter. It should work with your menu implementation as well. Since you're defining the menu by XML, the below will also work for you as long as you reference the menu resource. Here's what the result looks like:
Override onCreateContextMenu or your menu's relevant onCreate.. method like so within the:
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
menu.setHeaderTitle(getStr(R.string.actions_title));
// Groups 0 and 1, first parameter for menu.add()
menu.add(0, getAdapterPosition(), 0, R.string.homescreen);
menu.add(0, getAdapterPosition(), 1, R.string.lockscreen);
menu.add(0, getAdapterPosition(), 2, R.string.wpLocation_both);
menu.add(1, getAdapterPosition(), 3, R.string.action_download);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
menu.setGroupDividerEnabled(true); // This adds the divider between groups 0 and 1, but only supported on Android 9.0 and up.
}
}
OK, I've found a nice workaround, but I'm not sure the styling should be this way. That's what I'm missing:
background of items is on top of the background of the popup of the spinner, and I'm not sure if that's the correct way to put it.
I used the white background of the support library for the popup of the spinner. I think there should be a better way to make it white.
I need to know what is the correct style of the divider. for now I used a simple one
Action bar item style is missing. I just used a simple ImageView, and I think it should be different.
For some reason, on some Android versions (maybe Lollipop and below) the background of the items look black instead of white.
The spinner might sometimes have issues with setOnItemSelectedListener , not sure when.
MainActivity
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
final MenuItem item = menu.findItem(R.id.action_settings);
final Spinner spinner = ((Spinner) MenuItemCompat.getActionView(item));
SimpleImageArrayAdapter adapter = new SimpleImageArrayAdapter(this);
spinner.setAdapter(adapter);
return true;
}
public class SimpleImageArrayAdapter extends ArrayAdapter<String> {
private final String[] items = {"item 1", "item 2", "item 3", "extra item"};
public SimpleImageArrayAdapter(Context context) {
super(context, 0);
}
#Override
public int getCount() {
return items.length;
}
#Override
public String getItem(final int position) {
return items[position];
}
#Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
View rootView = convertView == null ? LayoutInflater.from(getContext()).inflate(R.layout.spinner_item, parent, false) : convertView;
TextView tv = (TextView) rootView.findViewById(android.R.id.text1);
tv.setTextColor(0xff000000);
tv.setText(items[position]);
boolean isLastItem = position == getCount() - 1;
rootView.findViewById(R.id.action_divider).setVisibility(isLastItem ? View.VISIBLE : View.GONE);
rootView.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
return rootView;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
//this is the view that's shown for the spinner when it's closed
ImageView iv = new ImageView(getContext());
iv.setImageResource(android.R.drawable.ic_menu_add);
int viewSize = getDimensionFromAttribute(MainActivity.this, android.support.v7.appcompat.R.attr.actionBarSize);
iv.setLayoutParams(new ViewGroup.LayoutParams(viewSize, viewSize));
iv.setScaleType(ScaleType.CENTER_INSIDE);
iv.setBackgroundResource(getResIdFromAttribute(MainActivity.this, R.attr.selectableItemBackground));
return iv;
}
}
public static int getResIdFromAttribute(final Activity activity, final int attr) {
if (attr == 0)
return 0;
final TypedValue typedValue = new TypedValue();
activity.getTheme().resolveAttribute(attr, typedValue, true);
return typedValue.resourceId;
}
public static int getDimensionFromAttribute(final Context context, final int attr) {
final TypedValue typedValue = new TypedValue();
if (context.getTheme().resolveAttribute(attr, typedValue, true))
return TypedValue.complexToDimensionPixelSize(typedValue.data, context.getResources().getDisplayMetrics());
return 0;
}
res/menu/menu_main.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.example.user.myapplication.MainActivity">
<item
android:id="#+id/action_settings"
android:actionLayout="#layout/spinner"
android:title=""
app:actionLayout="#layout/spinner"
app:showAsAction="always"
/>
</menu>
res/layout/spinner_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="#+id/action_divider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/divider"/>
<TextView
android:id="#android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical"
android:minHeight="?attr/listPreferredItemHeightSmall"
android:paddingEnd="?attr/listPreferredItemPaddingRight"
android:paddingLeft="?attr/listPreferredItemPaddingLeft"
android:paddingRight="?attr/listPreferredItemPaddingRight"
android:paddingStart="?attr/listPreferredItemPaddingLeft"
android:textAppearance="?attr/textAppearanceListItemSmall"/>
</LinearLayout>
res/layout/spinner.xml
<?xml version="1.0" encoding="utf-8"?>
<Spinner
android:id="#+id/spinner"
style="#style/SpinnerWithoutArrow"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
res/values/styles.xml
<style name="SpinnerWithoutArrow" parent="#style/Widget.AppCompat.Spinner">
<item name="android:background">#null</item>
<item name="android:popupBackground">#drawable/abc_popup_background_mtrl_mult</item>
</style>
res/drawable/divider.xml
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<size
android:height="1dp"/>
<solid android:color="#FFff0000" />
</shape>
This can be done by using popup window and list view. In your list view, you can have different view types, such as menu item and divider.
I list the code for popup window part:
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.option_menu, null);
ListView listView = (ListView) view.findViewById(R.id.listView);
listView.setDivider(null);
mAdapter = new OptionListAdapter(context, options);
listView.setAdapter(mAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//TODO: The code when item is clicked.
}
});
mPopupWindow = new PopupWindow(context, null, R.attr.popupMenuStyle);
mPopupWindow.setFocusable(true); // otherwise on android 4.1.x the onItemClickListener won't work.
mPopupWindow.setContentView(view);
mPopupWindow.setOutsideTouchable(true);
int height = 0;
int width = 0;
float density = context.getResources().getDisplayMetrics().density;
int minWidth = Math.round(196 * density); // min width 196dip, from abc_popup_menu_item_layout.xml
int cellHeight = context.getResources().getDimensionPixelOffset(R.dimen.option_height);
int dividerHeight = context.getResources().getDimensionPixelOffset(R.dimen.divider_height);
final int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
final int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
for (int i = 0; i < mAdapter.getCount(); i++) {
Object item = mAdapter.getItem(i);
if (item != null) {
View childView = mAdapter.getView(i, null, listView);
childView.measure(widthMeasureSpec, heightMeasureSpec);
height += cellHeight;
width = Math.max(width, childView.getMeasuredWidth());
} else {
height += dividerHeight; // divider
}
}
width = Math.max(minWidth, width);
Drawable background = mPopupWindow.getBackground(); // 9-pitch images
if (background != null) {
Rect padding = new Rect();
background.getPadding(padding);
height += padding.top + padding.bottom;
width += padding.left + padding.right;
}
mPopupWindow.setWidth(width);
mPopupWindow.setHeight(height);
mPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
Then you can use following method to show the popup window:
PopupWindowCompat.showAsDropDown(mPopupWindow, parent, x, y, gravity);
In the adapter for list view, you can override getViewTypeCount() and getItemViewType() to support both menu item layout and divider layout, also you can add any view type that you need.
Here is a snapshot in my app:
In Material3 Design, MDC-Android, make menu items in each group, and call setGroupDividerEnabled(Boolean).
Dividers will inserted between group or menu item(s).
MyActivity.kt
private val binding by lazy { ActivityMyBinding.inflate(layoutInflater) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
// other initializations..
// ...
binding.toolbar.menu.setGroupDividerEnabled(true)
}
activity_my.xml
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
<!-- Other properties -->
android:id="#+id/toolbar"
app:menu="#menu/main" />
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
menu.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/item0"
android:title="item0"
app:showAsAction="never" />
<item
android:id="#+id/item1"
android:title="item1"
app:showAsAction="never" />
<group android:id="#+id/group0">
<item
android:id="#+id/item2"
android:title="group0 item2"
app:showAsAction="never" />
</group>
<group android:id="#+id/group1">
<item
android:id="#+id/item3"
android:title="group1 item3"
app:showAsAction="never" />
<item
android:id="#+id/item4"
android:title="group1 item4"
app:showAsAction="never" />
</group>
</menu>
I did it this way:
Reference screenshot:
style.xml:
<style name="popup" parent="Widget.AppCompat.ListView.DropDown">
<item name="android:divider">#color/colorPrimary</item>
<item name="android:dividerHeight">1dp</item>
<item name="android:textColor">#color/colorPrimary</item>
<item name="android:itemBackground">#android:color/white</item>
</style>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!--- Customize popmenu -->
<item name="android:dropDownListViewStyle">#style/popup</item>
</style>
Java code:
private void showPopup(View v) {
Context wrapper = new ContextThemeWrapper(this, R.style.popup);
PopupMenu mypopupmenu = new PopupMenu(wrapper, v);
MenuInflater inflater = mypopupmenu.getMenuInflater();
inflater.inflate(R.menu.menu_patient_language, mypopupmenu.getMenu());
mypopupmenu.show();
mypopupmenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
txtPreferredLanguage.setText(item.getTitle().toString());
switch (item.getItemId()) {
case R.id.menuEnglish:
// Your code goes here
break;
case R.id.menuFrench:
// Your code goes here
break;
}
return false;
}
});
}
Hope this will help you.
Super simple solution that worked out for me:
Define a drawable for the background:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#android:color/white"/>
<stroke
android:width="3dp"
android:color="#color/colorPrimary"/>
</shape>
then in Styles use the background:
<style name="bluetooth_popup" parent="#android:style/Widget.DeviceDefault.Light.PopupMenu">
<item name="android:textColor">#color/colorPrimary</item>
<item name="android:textStyle">bold</item>
<item name="android:textAllCaps">true</item>
<item name="android:background">#android:color/transparent</item>
<item name="android:itemBackground">#drawable/bluetooth_popup_buttons</item>
now :
group1[ item0 item1 item2 ] group1[item3];
change to :
group1[ item0 item1] group1[item2 item3]
group has a divider;
it likes that group can add a divder between item;
if divider is unavailable,try background;
i never user menu;
its my guess;
I'm trying to implement onClickListener for the item which is a submenu of the ActionBar. Whatever I'm trying to do the result is the same - "Unfortunatelly, application has stopped." However there are no errors during compilation. All seems to be ok, but it is't. What goes wrong here? Thanks for help.
This is my code:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
View view = (View) menu.findItem(R.id.delete).getActionView();
view.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Execute when actionbar's item is touched
}
});
return true;
}
And here is the main.xml file where ActionBar and its item is created
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="#+id/action_settings"
android:orderInCategory="100"
android:showAsAction="always"
android:title="#string/action_settings">
<menu>
<item
android:id="#+id/delete"
android:title="#string/delete"
android:showAsAction="always"
android:orderInCategory="200"/>
</menu>
</item>
</menu>
getActionView() returns a valid object (not null) only you have a custom action view (with setActionView)