I'm having real difficulty doing anything to the overflow menu in actionbar sherlock.
Ideally, I would like to use a custom TextView for each item in order to set a different font on it and change the colour of the pressed state.
I have tried (all without success):
Changing The Style Of Actionbar Overflow
Actionbar styled overflow menu items
listview as action overflow in sherlock actionbar
https://groups.google.com/forum/#!msg/actionbarsherlock/5lHOKNlXn_4/f9XicMXbFFAJ
My app will have different fragments, all extending BaseFragment with different items in the overflow menu. I'm also using the v4 support package. I'm creating my menu like this:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.activity_borrow, menu);
}
activity_borrow.xml:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#+id/menu_filter"
android:title="test"
android:orderInCategory="100"
android:showAsAction="never"
/>
</menu>
My app uses a theme that inherits from Theme.Sherlock.
How can I used a custom view inside that menu? Or at the very least, how can I change the default blue pressed state?
To change the colors of the overflow list items, add two items to your application theme which is usually defined in res/values/styles.xml:
<item name="android:dropDownListViewStyle">#style/DropDownListView</item>
<item name="dropDownListViewStyle">#style/DropDownListView</item>
In that same file, add the style that you have just assigned:
<style name="DropDownListView" parent="#style/Widget.Sherlock.ListView.DropDown">
<item name="android:listSelector">#drawable/selectable_background</item>
</style>
And finally create a selector drawable selectable_background.xml in the drawable folder, containing this:
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:exitFadeDuration="#android:integer/config_mediumAnimTime" >
<item android:state_pressed="false" android:state_focused="true" android:drawable="#color/focussed_color" />
<item android:state_pressed="true" android:drawable="#color/pressed_color" />
<item android:drawable="#android:color/transparent" />
</selector>
Finally, define the colors which are usually placed in colors.xml:
<resources>
<color name="pressed_color">#FF8E4067</color> <!-- your purple tone already ;) -->
<color name="focussed_color">#DD8E4067</color>
</resources>
In my app, I used the "ActionBar Style Generator" as baboo suggested, which handles everything for you conveniently. For this answer, I just extracted and simplified the parts that I think make up the overflow menu styling.
I think there is some mystery about the effects of styling three different items:
From my understanding, android:dropDownListViewStyle includes the
overflow menu that hides behind the "three dots" in the ActionBar.
Not to be confused with android:actionDropDownStyle, which is used to the style the app navigation dropdown in case you used actionBar.setNavigationMode(NAVIGATION_MODE_LIST)
However, some Android devices with a hardware menu button (e.g. the Nexus S or Galaxy S3 Mini)
don't display the "three dots" but an overlay menu that slides in from
the bottom of the screen if the hardware menu button is clicked. android:popupMenuStyle is the correct attribute to style this.
Again, this is only as far as I can remember from my own app development.
Also, make sure to check that no other style files (e.g. folders with configuration qualifiers) overwrite the styles that you have just defined.
All in all, I understand that this would only change the background color of the list items. To use a completely custom view in there, you might create a custom spinner view, add a dummy button with a "three dots" icon to your ActionBar and open the spinner on click.
Related
I have created a menu and now I want to change the text color of the individual menu titles.
To do this, I first created a style that should contain the corresponding attribute and then called this style in my Activity_home_drawer.xml. However, this only changes the menu TextColor when the corresponding menu title is clicked but is not permanent as I would like it to be.
What do I have to do so that the text color in my menu changes permanently to white and not Black anymore? Is my way of doing it the right way or is there a more elegant way to change the TextColor?
Thanks for any help!
Part of my Activity_home_drawer.xml
<?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"
android:theme="#style/TextAppearance44">
<group android:id="#+id/category_group">
<item
android:id="#+id/nav_menu"
android:icon="#drawable/ic_store_black_24dp"
android:title="#string/menu_menu"
android:theme="#style/TextAppearance44"
/>
</group>
My TextAppearance44 style
<style name="TextAppearance44">
<item name="android:textColor">#color/colorWhite</item>
<item name="android:actionMenuTextColor">#color/colorWhite</item>
<item name="android:textSize">16sp</item>
<item name="android:titleTextColor">#color/colorWhite</item>
</style>
You need to change your ToolBar style. Check these two tutorials:
Toolbar assigning to activity and styling:
https://android-developers.googleblog.com/2014/10/appcompat-v21-material-design-for-pre.html?m=1
Changing style and items colors in the Toolbar:
https://www.murrayc.com/permalink/2014/10/28/android-changing-the-toolbars-text-color-and-overflow-icon-color/
In your case, you are looking mainly for (code fragment from second tutorial):
<!-- android:actionMenuTextColor is the color of the text of
action (menu) items in the Toolbar, at least in the
Theme.AppCompat theme.
For some reason, they already get the textColorPrimary
when running on API 21, but not on older versions of
Android, so this is only necessary to support older
Android versions.-->
<item name="actionMenuTextColor">#color/abc_primary_text_material_light</item>
I solved it by myself; I added these to lines to my NavigationView in my ActivityHome (where the Menu comes up).
app:itemTextColor="#color/colorWhite"
app:itemIconTint="#color/colorWhite"
Simple mistake, didnot know that there was such a attribute.
With Theme.Holo.Light as the base theme, a designer noticed that the default text colour is not black, but a dark grey (#505050). We'd like to change it to black.
Looking for a simple way to change the default to black everywhere in the app, I found that this works:
<resources>
<style name="MyAppTheme" parent="android:Theme.Holo.Light">
<item name="android:textColor">#android:color/black</item>
</style>
</resources>
Now, problem is, that also changes the colour of disabled items in Action Bar's overflow menu. How to override default text colour while still having disabled menu items look "disabled"?
The menu should look something like below, but using android:textColor as above, it changes all the items to black.
I was experimenting with textColorPrimaryInverse, textColorPrimaryDisableOnly, textColorPrimaryInverseDisableOnly and disabledAlpha but those didn't seem to affect the overflow menu.
You can use a drawable as the text colour, and in drawable you can use selector to select the colour according to enabled status. Using following drawable definition as colour will make your disabled menu items grey and the rest black.
In e.g. res/drawable/default_text_colour.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false" android:color="#android:color/darker_gray"/>
<item android:color="#android:color/black"/>
</selector>
Then, using the drawable:
<item name="android:textColor">#drawable/default_text_colour</item>
I'm having a problem when I try to set one item in my actionbar as always visible and 4 more icons as dropdown items with the following layout:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="#+id/search_movies"
android:icon="#drawable/action_search"
android:showAsAction="always"
android:title="Search"/>
<item
android:id="#+id/movies"
android:icon="#drawable/action_video"
android:showAsAction="collapseActionView"
android:title="Movies"/>
<item
android:id="#+id/theaters"
android:icon="#drawable/action_location_map"
android:showAsAction="collapseActionView"
android:title="Theaters"/>
<item
android:id="#+id/preferences"
android:icon="#drawable/action_settings"
android:showAsAction="collapseActionView"
android:title="Preferences"/>
<item
android:id="#+id/contact"
android:icon="#drawable/action_about"
android:showAsAction="collapseActionView"
android:title="Contact"/>
</menu>
The result is just the first item showing and the rest are not visible, not even as a dropdown. This is using ActionBarSherlock and a 2.3 Android device.
The question is, how can I get the icons to follow this layout:
EDIT:
The problem I had was because when you are using the actionbar with a device that has a "menu" hardware button the 3-dot dropdown does not shows off, the 4 other items are only displayed if you press the menu hardware button. Does anyone knows if this behaviour can be modified?
Hmmm, maybe I misunderstood, but if you wish to places those remaining four items into the overflow action menu (the 3-dot icon) then using android:showAsAction="never" instead of "collapseActionView" should do it.
...Tried a couple ways, but this did the trick:
Force overflow menu in ABS
I've met the same problem and my solution is quite simple. (I didn't use HoloEverywhere.)
The idea comes from the ABS sample project, whose drop-down menu can be displayed on pre-4.0 devices as well by using a submenu. So, my idea is using a submenu to disguise the 3-dot icon. Here's the code:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
SubMenu sub = menu.addSubMenu("More");
sub.getItem().setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
sub.getItem().setIcon(R.drawable.ic_menu);
getSupportMenuInflater().inflate(R.menu.activity_main, sub);
return true;
}
Since the "More" menu doesn't have a MenuItem.SHOW_AS_ACTION_WITH_TEXT attribute, so the word "More"(or whatever you named) will actually not be displayed on the action bar. The only displayed icon R.drawable.ic_menu can be copied from ABS source code res/drawable-xxdpi folders named "abs__ic_menu_moreoverflow_normal_holo_dark.png", which is the so-called 3-dot icon. And the R.menu.activity_main is your menu xml.
It works!
In my app the user can choose from 4 different themes. The time has come to create different menu icons for the different themes, but the icons do not show in the menu items. Any ideas?
Menu:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#+id/Menu1"
android:orderInCategory="1"
style="?menu_addtolist" />
attrs.xml
<attr name="menu_addtolist" format="reference" />
themes.xml
<item name="menu_addtolist">#style/menu_green_addtolist</item>
styles.xml
<style name="menu_green_addtolist">
<item name="android:src">#drawable/menu_addtolist_green</item>
</style>
I did everything the way I had done with the other objects (buttons, layouts, texts). When I select a theme, the full theme changes, but there are no menu icons.
I changed the style in the menu item to another one I use in the app as a button style, and that did not make a change, while that style is definitely working. Maybe it is not possible to apply styles to menu items?
It looks like the answer is no. It is not possible to use themes with menu. Maybe because the menu has no (available) layout
There's a question for the same functionality on Blackberry, and a few different threads referred to this bug (which has since been closed without resolution as far as I can tell), but I haven't found one specifically for Android.
I'm calling setEnabled(false) on certain MenuItems based on some state, but they visually look the same. I'd like them to be offset in some way, so that the user knows that the option currently isn't available -- is there any way to do that?
On all android versions, easiest way to use this to SHOW a menu action icon as disabled AND make it FUNCTION as disabled as well:
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem item = menu.findItem(R.id.menu_my_item);
if (myItemShouldBeEnabled) {
item.setEnabled(true);
item.getIcon().setAlpha(255);
} else {
// disabled
item.setEnabled(false);
item.getIcon().setAlpha(130);
}
}
I had the same issue. There are two ways of getting this to work:
Put your icons in a StateList so that a different icon will be used on disable
What I use now. Change the icon yourself with something like this in onPrepareOptionsMenu():
public boolean onPrepareOptionsMenu(Menu menu) {
boolean menusEnabled = reachedEndOfSlidehow(); // enable or disable?
MenuItem item = menu.findItem(R.id.menu_next_slide);
Drawable resIcon = getResources().getDrawable(R.drawable.ic_next_slide);
if (!menusEnabled)
resIcon.mutate().setColorFilter(Color.GRAY, PorterDuff.Mode.SRC_IN);
item.setEnabled(menusEnabled); // any text will be automatically disabled
item.setIcon(resIcon);
}
You can call invalidateOptionsMenu() (or from ABS, supportInvalidateOptionsMenu()) to rebuild the menu.
EDIT: Updated solution 2
Source: https://groups.google.com/forum/?fromgroups#!topic/actionbarsherlock/Z8Ic8djq-3o
I found a new way to solve this issue using a drawable selector xml file. You just create a selector with the icon you want to use in your menu item, then you can either change the tint, alpha or both of the bitmap:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="true">
<bitmap android:src="#drawable/ic_menu_item"
android:tint="#color/enabled_color"
android:alpha="#integer/enabled_alpha"/>
</item>
<item android:state_enabled="false">
<bitmap android:src="#drawable/ic_menu_item"
android:tint="#color/disabled_color"
android:alpha="#integer/disabled_alpha"/>
</item>
</selector>
As a side note; I like to set the tint to "?android:attr/textColorPrimary" for enabled state and "?android:attr/textColorHint" for disabled state. This way it will adjust depending on the theme used.
Then you can just set the icon in your menu xml file to the selector resource:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="#+id/menu_action"
android:orderInCategory="0"
android:title="#string/title_menu_action"
android:icon="#drawable/ic_menu_item_selector"
app:showAsAction="ifRoom"/>
</menu>
Then when you call item.setEnabled(enabled) the color and/or alpha of the icon will change along with the state!
The way I did it is by using "itemIconTint" in NavigationView, you can also grey out the text by using "itemTextColor"
This is Navigationview:
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:itemBackground="#color/white"
android:background="#color/white"
app:itemTextColor="#color/menu_text_color"
app:itemIconTint="#color/menu_text_color"
app:menu="#menu/main_drawer" />
and the "#color/menu_text_color" is a selector:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:color="#color/primaryColor" />
<item android:state_enabled="false" android:color="#color/disabled_text_color" />
<item android:color="#color/primaryText" />
</selector>
Finally, if you want to disable a menuitem,
MenuItem item = mNavigationView.getMenu().findItem(R.id.your_menu_item);
item.setEnabled(isEnable);
Done!
I was having difficulty with this on modern android with MaterialComponents theme. My problem was I had set <item name="actionMenuTextColor">#color/blue</item> in styles.xml and this overrides the text color whether the item is enabled or disabled. The solution is to set a Color state list and not a color directly.
My styles attribute now looks like:
<item name="actionMenuTextColor">#color/menu_color_selector</item>
I had an issue where neither my the text nor the icon was visibly changing. The other answers either didn't work for me or weren't very elegant. Here's an answer that works for the latest Material recommendations.
You should be able to simply call menu.findItem(R.id.menu_my_item).isEnabled = false in onPrepareOptionsMenu(menu: Menu).
(If you need onPrepareOptionsMenu to run again, you can simply call invalidateOptionsMenu() or activity?.invalidateOptionsMenu() (from a fragment) and the application will queue up the menu to be recreated. Alternatively you can store off the menu item in a member variable to modify it later, but be careful to destroy your reference to it within onDestroyOptionsMenu to avoid a memory leak.)
The fact that the menu item is disabled should be enough to grey out the text or the icon automatically. The difficulty is in setting up your styles to make this work.
Short Answer
First create a color state list my_color_state_list.xml that you want your icons and text to use (e.g. black when enabled, grey when disabled). (See the full answer for an example.)
If you're using com.google.android.material.appbar.MaterialToolbar, you can tell it to use this selector for icons and text by providing a custom theme overlay. In your activity's XML, give the toolbar the attribute android:theme="#style/Foo" and define that style somewhere as:
<style name="Foo">
<item name="colorControlNormal">#color/my_color_state_list</item>
<item name="actionMenuTextColor">#color/my_color_state_list</item>
</style>
Now when the menu item is enabled or disabled via menu.findItem(R.id.menu_my_item).isEnabled = false the text will automatically change color, and any icons which use the color ?attr/colorControlNormal will also automatically change color.
Full answer
My starting place
My menu items are part of a Material toolbar. This answer may help for other kinds of toolbar/app bar, but your mileage may vary. In my activity I have something like this:
<com.google.android.material.appbar.MaterialToolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:theme="#style/ThemeOverlay.MaterialComponents.Toolbar.Surface"/>
and the theme I'm using looks something like this:
<style name="Theme.MyApp" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<item name="colorPrimary">#color/blue</item>
<item name="colorSecondary">#color/green</item>
<item name="colorSurface">#color/lightGrey</item>
<item name="colorOnSurface">#color/black</item>
[...]
<item name="windowActionModeOverlay">true</item>
</style>
It is also convention that the icon you use in buttons and menu items (and everywhere really) should have their default color be ?attr/colorControlNormal. So for example I might have a vector image which looks like:
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal"
android:tintMode="src_atop">
<path android:pathData="..." android:fillColor="#android:color/white"/>
</vector>
If you download an icon from Material Icons you will see they all use colorControlNormal.
What I needed to do
If you look back at the definition of my toolbar, you will see it uses a ThemeOverlay ThemeOverlay.MaterialComponents.Toolbar.Surface which is defined as:
<style name="ThemeOverlay.MaterialComponents.Toolbar.Surface" parent="">
<item name="colorControlNormal">#color/material_on_surface_emphasis_medium</item>
<item name="actionMenuTextColor">#color/material_on_surface_emphasis_medium</item>
</style>
This sets the menu item text color and icon color to #color/material_on_surface_emphasis_medium which does not respond to being enabled or not. #color/material_on_surface_emphasis_medium looks like:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:alpha="#dimen/material_emphasis_medium" android:color="?attr/colorOnSurface"/>
</selector>
(You may be using ThemeOverlay.MaterialComponents.Toolbar.Primary instead, which has a similar issue - it simply uses colorOnPrimary.)
We need to replace this with our own color state list which responds to enabled state. So, make a new file res/color/menu_item_selector.xml that looks something like this:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="true" android:alpha="#dimen/material_emphasis_medium" android:color="?attr/colorOnSurface"/>
<item android:alpha="#dimen/material_emphasis_disabled" android:color="?attr/colorOnSurface"/>
</selector>
You see I've used the same conventions that the material library does by using their constants to define the alpha values, and I used colorOnSurface as my color. If you were using ThemeOverlay.MaterialComponents.Toolbar.Primary you would want colorOnPrimary instead. Of course you can use any color or alpha here, it's up to you.
And now make a new ThemeOverlay in res/values/styles.xml to point to this selector, inheriting from whatever ThemeOverlay you were using:
<!-- Toolbar - overrides the menu text color to use a selector that responds to whether it's enabled or not -->
<style name="ThemeOverlay.MyTheme.Toolbar" parent="ThemeOverlay.MaterialComponents.Toolbar.Surface">
<!-- Color used in the icons of menu actions (i.e. non-overflow menu items). This is just convention, this will affect anything that uses ?attr/colorControlNormal) -->
<item name="colorControlNormal">#color/menu_item_color_selector</item>
<!-- Color used in the text of menu actions (i.e. non-overflow menu items) -->
<item name="actionMenuTextColor">#color/menu_item_color_selector</item>
</style>
And now finally we can apply this ThemeOverlay to the toolbar:
<com.google.android.material.appbar.MaterialToolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:theme="#style/ThemeOverlay.MyTheme.Toolbar"/>
setEnabled(false) works fine on API Level < 14 but on 14 the item still clickable.
Have a look at this link
setEnabled can also be used for MenuItems.
Here's a simple way to do it (using Kotlin):
fun changeMenuItemColour(enabled: Boolean) {
var menuItem = SpannableString(mCustomToolbar?.menu?.findItem(R.id.some_menu_item)?.title)
var style = activity?.resources?.getColor(R.color.darkGraphite)!!
if (enabled) style = activity?.resources?.getColor(R.color.black)!!
menuItem.setSpan(ForegroundColorSpan(style), 0, menuItem.length, 0)
}