set actionbar icon height to match actionbar height - android

see the problem here, the grey checkbox leaves room from the top and bottom of the action bar:
styles.xml
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="CustomActionBarTheme" parent="Theme.Base.AppCompat.Light">
<item name="android:windowContentOverlay">#null</item>
<item name="android:actionButtonStyle">#style/ActionButtonStyle</item>
</style>
<!--<style name="ActionButtonStyle" parent="#android:style/Widget.Holo.Light.ActionButton">-->
<style name="ActionButtonStyle" >
<item name="android:height">#dimen/abc_action_bar_default_height</item>
<item name="android:layout_height">#dimen/abc_action_bar_default_height</item>
</style>
i set the item like so:
getMenuInflater().inflate(R.menu.submit_action, menu);
submit_action looks like:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="#+id/action_submit"
android:icon="#drawable/check"
app:showAsAction="always" />
</menu>
and finally, attached is the #drawable/check being used.
any idea how i can get the check to fill the actionbar?

The reason your icon doesn't fill the ActionBar is due to how the ActionMenuItemView measures the icon.
The ActionMenuItemView invokes a maximum size of 32dp when it sets the bounds for your icon
So, it makes so difference how large your image is, the system will always resize it.
any idea how i can get the check to fill the actionbar?
You should use a action layout for your MenuItem, a check mark icon with no background, and change the background color of the action layout parent as you see fit. Here's an example:
layout
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="?android:attr/actionButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#e8e8e8"
android:clickable="true"
android:contentDescription="#string/cd" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="#null"
android:scaleType="centerInside"
android:src="#drawable/ic_action_tick" />
</RelativeLayout>
MenuItem
<item
android:id="#+id/action_submit"
android:actionLayout="#layout/your_action_layout"
android:showAsAction="always"/>
Accessibility
It's important to make sure your MenuItem is accessible. Normally when you long press an item in the ActionBar a short Toast will display the content description for you, but when you're using a custom MenuItem it's up to you to implement this pattern. An easy way to do this is by using Roman Nurik's CheatSheet. If you're unsure how to use it, you should refer to my answer here that goes into much more detail on creating custom MenuItem layouts.
Alternatively
If you want to use that background color for every MenuItem you have, you could create a custom style and apply it using the android:actionButtonStyle attribute. Here's an example of that:
Your style
<style name="Your.ActionButton" parent="#android:style/Widget.Holo.Light.ActionButton">
<item name="android:background">#e8e8e8</item>
</style>
Your theme
<style name="Your.Theme" parent="#android:style/Theme.Holo.Light">
<item name="android:actionButtonStyle">#style/Your.ActionButton</item>
</style>
Results

Here's what I do with Icons in Android to get the sizing correct. You have an existing project with the res/drawable- folders. You have to put the correct Icon into the correct folder.
Start a new project wizard and when you get to the launcher icon put in the Icon you want to use in your existing project. finish the wizard. The wizard will make the various sizes of Icons for you. Then I manually copy the Icons from the res/drawable-xdpi res/drawable-ldpi etc to the corresponding folder on my existing project. Delete the new project it is no longer needed.

Related

Changing the Color of the the Menu Items does not work

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.

Remove extra background color rectangle from overflow menu enter/exit animations?

When I open the overflow menu in my application, I see a solid rectangle of the menu background color displayed behind the menu itself throughout the enter/exit animations. Here's an animation showing this (slowed to 75% speed):
The presence of this extraneous colored rectangle spoils the nice enter/exit animations! How can I remove it while retaining all other Toolbar styling?
Research
I've read a bunch of answers on Toolbar styling on SO, and Chris Banes' own posts on the subject. It seems that usage of the style/theme tags on a per-View basis has changed in the past couple years, which has made it difficult to find definitive information anywhere.
I've reproduced this using versions 22.1.0 through 23.2.0 (inclusive) of the support library.
App files
styles.xml
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
</style>
<style name="ToolbarStyle" parent="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<item name="android:background">#color/colorPrimary</item>
</style>
</resources>
activity_main.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:style="#style/ToolbarStyle" />
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Runtime View Analysis
As #Commonsware suggested, I took a look at the view hierarchy at run time. Editing in the results:
Menu collapsed (overflow button present, no mysterious extra rectangle):
Menu expanded (overflow menu views displayed in separate Window):
The main application view hierarchy (as displayed in the original Window) is unchanged when comparing the two menu (steady) states. My guess is therefore that the extra rectangle is temporarily added to the main application's window during menu animations, and immediately removed upon their completion. I'm not sure why this would be done - perhaps it's a hangover from an older (and now unused) method of showing and hiding the overflow menu? If my deduction is correct, then this question could be resolved if we can determine how to prevent this transitory behavior...
An extract from the Chris Bane's answer to the question AppCompat style background propagated to the Image within the ToolBar
style = local to the Toolbar
theme = global to everything inflated in the Toolbar
Based on the above post it seems, the android:background attribute you are setting in the android:theme is the reason for the extra background color during the animation.
I'd set the background to the toolbar directly and used the android:colorBackground attribute to set the background color for the popup. The animation seems to work fine.
Code:
activity_main.xml
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorPrimary"
android:theme="#style/CustomToolbarTheme" />
styles.xml
<style name="CustomToolbarTheme" parent="ThemeOverlay.AppCompat.Dark.ActionBar">
<item name="android:colorBackground">#color/colorPrimary</item>
<item name="android:textColorPrimary">#android:color/white</item>
</style>

How to reduce the space around rating bar in android

I have included a rating bar in android, and now I need to place a text view to immediate right if the rating bar.But I failed to do the same since, there is a lot of unwanted space (rectangular blue box) around the rating bar, which prevents me from placing the textview to its immediate right side. Is there any way to reduce this space around the rating bar , so that both the textview and the rating bar comes in same line and textview is placed next to the rating bar without a gap.Please help me with a good support! Thanks in advance! Here is my xml code for it.
<RatingBar
android:id="#+id/overall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="70dp"
android:numStars="5"
android:rating="0.0"
android:scaleX="0.4"
android:scaleY="0.4"
android:stepSize="0.01" />
You can use android default styles, Like:
style="#android:style/Widget.Holo.Light.RatingBar.Small"
in you xml layout. I am using above and have no space around it.
You can check variants here
I tried to use different suggestion but i was unsuccessful with the Android Rating bar removal of extra padding. All i did downloaded ic icons from https://material.io/icons/ and use star and star bordered icon and programmed them with switch cases.
While using the base style for the RatingBar, set the minHeight to 0dp. The base minHeight in the style itself was preventing the view from scaling down. Setting it to 0 should work as you expect a normal view (we set ours to wrap_content).
Tried to use the base (#android:style/Widget.RatingBar) and small (#android:style/Widget.DeviceDefault.RatingBar.Small and #android:style/Widget.Holo.Light.RatingBar.Small) but both fixed/limited the size of the the RatingBar regardless of what icon is used. Looking at their codes, it was no surprise.
<style name="Widget.RatingBar">
<item name="indeterminateOnly">false</item>
<item name="progressDrawable">#drawable/ratingbar_full</item>
<item name="indeterminateDrawable">#drawable/ratingbar_full</item>
<item name="minHeight">57dip</item>
<item name="maxHeight">57dip</item>
<item name="thumb">#null</item>
<item name="mirrorForRtl">true</item>
</style>
<style name="Widget.Material.RatingBar.Small" parent="Widget.RatingBar.Small">
<item name="progressDrawable">#drawable/ratingbar_small_material</item>
<item name="indeterminateDrawable">#drawable/ratingbar_small_material</item>
<item name="minHeight">16dp</item>
<item name="maxHeight">16dp</item>
</style>
<style name="Widget.Holo.Light.RatingBar.Small" parent="Widget.RatingBar.Small">
<item name="progressDrawable">#drawable/ratingbar_small_holo_light</item>
<item name="indeterminateDrawable">#drawable/ratingbar_small_holo_light</item>
<item name="minHeight">16dip</item>
<item name="maxHeight">16dip</item>
</style>
Setting the scales didn't work right either.

indeterminateProgressBar in ActionBar styling - padding issue

I want to put an indeterminate progress bar inside my ActionBar (using ActionBarSherlock). Everything works, but I want it to be the small progress bar. I use following style:
<style name="IndeterminateProgress" parent="#android:style/Widget.ProgressBar.Small">
<item name="android:progressBarPadding">32dp</item>
<item name="progressBarPadding">32dp</item>
<item name="android:itemPadding">32dp</item>
<item name="itemPadding">32dp</item>
</style>
<style name="Widget.Styled.ActionBar.Tiles" parent="Widget.Sherlock.Light.ActionBar">
<item name="android:indeterminateProgressStyle">#style/IndeterminateProgress</item>
<item name="android:progressBarPadding">32dp</item>
<item name="progressBarPadding">32dp</item>
<item name="android:itemPadding">32dp</item>
<item name="itemPadding">32dp</item>
</style>
The problem is that I cannot set the padding on the progress bar. As you can see above, I've tried every possible combination of itemPadding and progressBarPadding, etc.
The result is always the same:
Any ideas?
I found a working solution how to set indeterminate progress bar with proper size and padding. My solution doesn't use workaround with setActionView(). It is solution for built-in progress bar functionality, supported by native action bar (ActionBarSherlock). Progress bar is enabled/disabled via setProgressBarIndeterminateVisibility(boolean) method. I tested it on Android 2, 3, 4 and ldpi, mdpi, xhdpi.
AndroidManifest.xml:
<application
...
android:theme="#style/Theme.Example">
/res/values/styles.xml:
<resources xmlns:android="http://schemas.android.com/apk/res/android">
...
<style name="Theme.Example" parent="Theme.Sherlock">
<item name="actionBarStyle">#style/Example.ActionBar</item>
<item name="android:actionBarStyle">#style/Example.ActionBar</item>
</style>
<style name="Example.ActionBar" parent="Widget.Sherlock.ActionBar">
<item name="indeterminateProgressStyle">#style/Example.ActionBar.IndeterminateProgressBar</item>
<item name="android:indeterminateProgressStyle">#style/Example.ActionBar.IndeterminateProgressBar</item>
</style>
<style name="Example.ActionBar.IndeterminateProgressBar" parent="#android:style/Widget.ProgressBar.Large.Inverse">
<item name="android:indeterminateDrawable">#drawable/layer_list_ab_indeterminate_progress_bar</item>
<item name="android:minWidth">#dimen/ab_indeterminate_progress_bar_size</item>
<item name="android:maxWidth">#dimen/ab_indeterminate_progress_bar_size</item>
<item name="android:minHeight">#dimen/ab_indeterminate_progress_bar_size</item>
<item name="android:maxHeight">#dimen/ab_indeterminate_progress_bar_size</item>
</style>
</resources>
/res/drawable/layer_list_ab_indeterminate_progress_bar.xml:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<!--
/res/drawable-mdpi/ab_indeterminate_progress_bar asset is taken from
/sdk/platforms/android-18/data/res/mdpi/spinner_white_48.png
and its content (optical square) is resized to ~0.6 (must be even number)
/res/drawable-mdpi-v14/ab_indeterminate_progress_bar asset is taken from
/sdk/platforms/android-18/data/res/mdpi/spinner_48_outer_holo.png
and its content (optical square) is resized to 0.75
-->
<rotate
android:drawable="#drawable/ab_indeterminate_progress_bar"
android:interpolator="#android:anim/linear_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:fromDegrees="0"
android:toDegrees="360" />
</item>
</layer-list>
/res/values/dimens.xml:
<dimen name="ab_indeterminate_progress_bar_size">48dp</dimen>
Finally I created progress bar assets. I used these two assets from Android SDK:
/sdk/platforms/android-18/data/res/mdpi/spinner_white_48.png for Honeycomb and older
/sdk/platforms/android-18/data/res/mdpi/spinner_48_outer_holo.png for ICS and newer
To get proper size and padding, we need to resize the assets. I resized spinner_white_48.png to ~0.6. For mdpi, it was 28px. It must be even number to be centrally symmetric. I resized only the content, not the whole icon. So icon in mdpi has still 48px, but its content (optical square) is smaller (28px). You can easily resize the content this way: first change "image size" to 28px X 28px, then change "canvas size" back to 48px X 48px. I resized spinner_48_outer_holo.png to 0.75. You can download the assets below.
Why do I use different assets for Honeycomb- and ICS+? Because if I'm using only Holo assets, the animation is little bit snatchy on some devices with Honeycomb-.
Tip: you can add another item with some animation to layer_list_ab_indeterminate_progress_bar.xml. For example standard Holo progress bar uses 2 animations with opposite direction and different degrees range. See progress_medium_holo.xml in SDK.
/res/drawable-mdpi/ab_indeterminate_progress_bar.png:
/res/drawable-mdpi-v14/ab_indeterminate_progress_bar.png (hardly visible on this page):
/res/drawable-hdpi/ab_indeterminate_progress_bar.png:
/res/drawable-hdpi-v14/ab_indeterminate_progress_bar.png (hardly visible on this page):
/res/drawable-xhdpi/ab_indeterminate_progress_bar.png:
/res/drawable-xhdpi-v14/ab_indeterminate_progress_bar.png (hardly visible on this page):
I don't know the exact answer but these settings worked for me..
This is my refresh_spinner.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center">
<ProgressBar android:layout_width="32dp"
android:layout_height="32dp"
android:layout_gravity="center"
android:layout_marginRight="12dp"
android:layout_marginLeft="12dp"
style="?indeterminateProgressStyle" />
</FrameLayout>
And this in the corresponding style xml
<style name="Widget.MyTheme.ActionBar" parent="Widget.Sherlock.ActionBar">
<item name="indeterminateProgressStyle">?android:attr/progressBarStyleSmallInverse</item>
</style>
These settings worked for me.
Please let me know if you have any doubts.
Regards
Parvaz Bhaskar
EDIT2 : since I was trying different methods I ended up using ?android:attr/progressBarStyleSmallInverse
as the only property in my style.xml which i later refrenced it from my spinner xml under style as style="?indeterminateProgressStyle"
EDIT:
keep a reference of your menuItem and whenever you want to show a refresh progressbar use setActionView(R.layout.your_layout), and change it to null when the need is over. onCreateOptionsMenu would be a good place to grab the menuItem at start.
I meet this today and find a solution for Android 3/4+
ProgressBar mProgressBarInActionBar = null;
Resources res = Resources.getSystem();
int id = res.getIdentifier("progress_circular", "id", "android");
View internal = findViewById(id);
if(internal != null && internal instanceof ProgressBar){
mProgressBarInActionBar = (ProgressBar)internal;
}
mProgressBarInActionBar.setPadding(0, 0, right, 0);
Set a suitable right :)
I had the same problem and I found an easy answer:
<style name="ActionBarProgressBar.MyStyle" parent="#android:style/Widget.Holo.ProgressBar.Large">
<item name="android:minWidth">56dp</item>
<item name="android:maxWidth">56dp</item>
<item name="android:minHeight">35dp</item>
<item name="android:maxHeight">35dp</item>
</style>
The Width is the standard Actionbar item width. If you change the minHeight and maxHeight, then the image will scale both ways.
And here is the Actionbar styling where you set the appearance of the Indeterminate Progress:
<style name="action_bar_theme" parent="#android:style/Widget.Holo.ActionBar">
<item name="android:indeterminateProgressStyle">#style/ActionBarProgressBar.MyStyle</item>
</style>
And the definition in the Theme you are using (don't forget to use it in your manifest):
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:actionBarStyle">#style/action_bar_theme</item>
</style>

Is it possible to grey out (not just disable) a MenuItem in Android?

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

Categories

Resources