I'm developing an simple app to test the material design. I'm using com.android.support:appcompat-v7:21.0.0 and my activity looks like:
public class MyActivity extends ActionBarActivity {
...
}
The layout is defined as:
<LinearLayout 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"
tools:context=".MyActivity">
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="128dp"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimaryDark"/>
</LinearLayout>
Now i defined my theme following material guidelines:
<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
<item name="colorPrimary">#color/colorPrimary500</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark700</item>
</style>
I'd like to change the status bar color in pre Android 5 and set it to colorPrimaryDark but i can't find the way. I tried using:
getWindow().setStatusBarColor(..)
but setStatusBar color is available from level 21.
Why if i define a colorPrimaryDark in my theme and use appcompact the status bar doesn't change color?
Anyone can help?
While colouring the status bar is not supported <5.0, on 4.4 you can use a work around to achieve a darker colour:
Make the status bar translucent
<item name="android:windowTranslucentStatus">true</item>
Then use AppCompat's Toolbar for your appbar, making sure that it fits system windows:
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
...
android:fitsSystemWindows="true"/>
Make sure to set your toolbar as your activity's toolbar:
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
The toolbar stretches underneath the status bar, and the semi translucency of the status bar makes it appear to be a darker secondary colour. If that's not the colour you want, this combination allows you to fit a view underneath your status bar sporting the background colour of your choice (though it's still tinted darker by the status bar).
Kind of an edge case workaround due to 4.4 only, but there ya go.
The status bar is a system window owned by the operating system. On pre-5.0 Android devices, applications do not have permission to alter its color, so this is not something that the AppCompat library can support for older platform versions. The best AppCompat can do is provide support for coloring the ActionBar and other common UI widgets within the application.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
getWindow().setStatusBarColor(getResources().getColor(R.color.actionbar));
}
Put this code in your Activity's onCreate method. This helped me.
As others have also mentioned, this can be readily solved by adding the following to the onCreate() of the Activity:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getWindow().setStatusBarColor(ContextCompat.getColor(this, R.color.primary_dark));
}
However, the important point I want to add here is that in some cases, even the above does not change the status bar color. For example, when using MikePenz library for Navigation Drawer, it implicityly overrides the status bar color, so that you need to manually add the following for it to work:
.withStatusBarColorRes(R.color.status_bar_color)
Status bar coloring is not supported in AppCompat v7:21.0.0.
From the Android developers blog post
On older platforms, AppCompat emulates the color theming where possible. At the moment this is limited to coloring the action bar and some widgets.
This means the AppCompat lib will only color status bars on Lollipop and above.
Switch to AppCompatActivity and add a 25 dp paddingTop on the toolbar and turn on
<item name="android:windowTranslucentStatus">true</item>
Then, the will toolbar go up top the top
This solution sets the statusbar color of Lollipop, Kitkat and some pre Lollipop devices (Samsung and Sony).
The SystemBarTintManager is managing the Kitkat devices ;)
#Override
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
hackStatusBarColor(this, R.color.primary_dark);
}
#SuppressLint("NewApi")
#SuppressWarnings("deprecation")
public static View hackStatusBarColor( final Activity act, final int colorResID ) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
try {
if (act.getWindow() != null) {
final ViewGroup vg = (ViewGroup) act.getWindow().getDecorView();
if (vg.getParent() == null && applyColoredStatusBar(act, colorResID)) {
final View statusBar = new View(act);
vg.post(new Runnable() {
#Override
public void run() {
int statusBarHeight = (int) Math.ceil(25 * vg.getContext().getResources().getDisplayMetrics().density);
statusBar.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, statusBarHeight));
statusBar.setBackgroundColor(act.getResources().getColor(colorResID));
statusBar.setId(13371337);
vg.addView(statusBar, 0);
}
});
return statusBar;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
else if (act.getWindow() != null) {
act.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
act.getWindow().setStatusBarColor(act.getResources().getColor(colorResID));
}
return null;
}
private static boolean applyColoredStatusBar( Activity act, int colorResID ) {
final Window window = act.getWindow();
final int flag;
if (window != null) {
View decor = window.getDecorView();
if (decor != null) {
flag = resolveTransparentStatusBarFlag(act);
if (flag != 0) {
decor.setSystemUiVisibility(flag);
return true;
}
else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
act.findViewById(android.R.id.content).setFitsSystemWindows(false);
setTranslucentStatus(window, true);
final SystemBarTintManager tintManager = new SystemBarTintManager(act);
tintManager.setStatusBarTintEnabled(true);
tintManager.setStatusBarTintColor(colorResID);
}
}
}
return false;
}
public static int resolveTransparentStatusBarFlag( Context ctx ) {
String[] libs = ctx.getPackageManager().getSystemSharedLibraryNames();
String reflect = null;
if (libs == null)
return 0;
final String SAMSUNG = "touchwiz";
final String SONY = "com.sonyericsson.navigationbar";
for (String lib : libs) {
if (lib.equals(SAMSUNG)) {
reflect = "SYSTEM_UI_FLAG_TRANSPARENT_BACKGROUND";
}
else if (lib.startsWith(SONY)) {
reflect = "SYSTEM_UI_FLAG_TRANSPARENT";
}
}
if (reflect == null)
return 0;
try {
Field field = View.class.getField(reflect);
if (field.getType() == Integer.TYPE) {
return field.getInt(null);
}
} catch (Exception e) {
}
return 0;
}
#TargetApi(Build.VERSION_CODES.KITKAT)
public static void setTranslucentStatus( Window win, boolean on ) {
WindowManager.LayoutParams winParams = win.getAttributes();
final int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
if (on) {
winParams.flags |= bits;
}
else {
winParams.flags &= ~bits;
}
win.setAttributes(winParams);
}
I know this doesn't answer the question, but with Material Design (API 21+) we can change the color of the status bar by adding this line in the theme declaration in styles.xml:
<!-- MAIN THEME -->
<style name="AppTheme" parent="#android:style/Theme.Material.Light">
<item name="android:actionBarStyle">#style/actionBarCustomization</item>
<item name="android:spinnerDropDownItemStyle">#style/mySpinnerDropDownItemStyle</item>
<item name="android:spinnerItemStyle">#style/mySpinnerItemStyle</item>
<item name="android:colorButtonNormal">#color/myDarkBlue</item>
<item name="android:statusBarColor">#color/black</item>
</style>
Notice the android:statusBarColor, where we can define the color, otherwise the default is used.
Make Theme.AppCompat style parent
<style name="AppTheme" parent="Theme.AppCompat">
<item name="android:colorPrimary">#005555</item>
<item name="android:colorPrimaryDark">#003333</item>
</style>
And put getSupportActionBar().getThemedContext() in onCreate().
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
getSupportActionBar().getThemedContext();
}
**
Solution for naughty LOLLIPOP
**
hello i had rly big problem with having that darker than was my color... so this is solution to avoid that shadow behind status bar from solution with TranslucentStatus...
so in all of your java activity you need this:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
and at your styles.xml you need to set background color (this color will be your status bar color):
<style name="AppCompat" parent="Theme.AppCompat">
<item name="android:colorBackground">#color/YOUR_STATUS_BAR_COLOR</item>
</style>
and at all your layouts you need to add layout which will be your background:
<LinearLayout
android:background="#color/YOUR_BACKGROUND_COLOR"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom"
/>
of course if you would like use #color/just name... you need to set that at colors.xml:
<color name="YOUR_STATUS_BAR_COLOR">#cf031c</color>
<color name="YOUR_BACKGROUND_COLOR">#383838</color>
here is whole process how we did done that: Whats the right approach to create or change color of a status bar?
I have an application that uses a preference activity to set some user settings. I been trying to figure this out all day. I am trying to theme the alert dialog when an user presses an Edit Text Preference object. A dialog opens up and the user can set the shared preference. The dialog pops up:
I want the text green. I want the divider green. The line and cursor green.
This is what I have so far.
<style name="CustomDialogTheme" parent="#android:style/Theme.Dialog">
<item name="android:background">#color/text_green</item>
<item name="android:textColor">#color/text_green</item>
</style>
Can someone point me in the right direction or maybe share some code. I am at lost. I've been surfing the net to find something most of the day. Thanks in advance.
If you don't want to create a custom layout or use a third party library, you can subclass EditTextPreference, then access each View you want to edit by using Resources.getIdentifier then using Window.findViewById. Here's a quick example.
public class CustomDialogPreference extends EditTextPreference {
public CustomDialogPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CustomDialogPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* {#inheritDoc}
*/
#Override
protected void showDialog(Bundle state) {
super.showDialog(state);
final Resources res = getContext().getResources();
final Window window = getDialog().getWindow();
final int green = res.getColor(android.R.color.holo_green_dark);
// Title
final int titleId = res.getIdentifier("alertTitle", "id", "android");
final View title = window.findViewById(titleId);
if (title != null) {
((TextView) title).setTextColor(green);
}
// Title divider
final int titleDividerId = res.getIdentifier("titleDivider", "id", "android");
final View titleDivider = window.findViewById(titleDividerId);
if (titleDivider != null) {
titleDivider.setBackgroundColor(green);
}
// EditText
final View editText = window.findViewById(android.R.id.edit);
if (editText != null) {
editText.setBackground(res.getDrawable(R.drawable.apptheme_edit_text_holo_light));
}
}
}
Implementation
Replace <EditTextPreference.../> with <path_to_CustomDialogPreference.../> in your xml.
Note
I used Android Holo Colors to create the background for the EditText.
You can build your custom layout for your own dialog theme using your own customized components or you can use external libs, for example android-styled-dialogs
So in this case use can customize dialogs as you want:
<style name="DialogStyleLight.Custom">
<!-- anything can be left out: -->
<item name="titleTextColor">#color/dialog_title_text</item>
<item name="titleSeparatorColor">#color/dialog_title_separator</item>
<item name="messageTextColor">#color/dialog_message_text</item>
<item name="buttonTextColor">#color/dialog_button_text</item>
<item name="buttonSeparatorColor">#color/dialog_button_separator</item>
<item name="buttonBackgroundColorNormal">#color/dialog_button_normal</item>
<item name="buttonBackgroundColorPressed">#color/dialog_button_pressed</item>
<item name="buttonBackgroundColorFocused">#color/dialog_button_focused</item>
<item name="dialogBackground">#drawable/dialog_background</item>
</style>
I have an activity which is shown in a dialog:
In order to remove border and rounded corners, i tried this:
<resources>
<style name="ActivityDialog" parent="#android:style/Theme.Dialog">
<item name="android:windowBackground">#null</item>
<item name="android:windowFrame">#null</item>
</style>
The border is gone, but sadly also the margin around the dialog.
Without creating a custom background drawable and adding a special style just add one line to your code:
dialog.getWindow().setBackgroundDrawableResource(android.R.color.transparent);
The border, round corners and margin are all defined by android:windowBackground. (Parameter android:windowFrame is already set to #null in Theme.Dialog style, therefore setting it to #null again has no effect.)
In order to remove the border and round corners you have to change the android:windowBackground appropriately. The Theme.Dialog style sets it to #android:drawable/panel_background. Which is a 9-patch drawable that looks like this (this one is the hdpi version):
As you can see the 9-patch png defines the margin, border and round corners of the dialog theme. To remove the border and round corners you have to create an appropriate drawable. If you want to keep the shadow gradient you have to create set of new 9-patch drawables (one drawable for each dpi). If you don't need the shadow gradient you can create a shape drawable.
The required style is then:
<style name="ActivityDialog" parent="#android:style/Theme.Dialog">
<item name="android:windowBackground">#drawable/my_custom_dialog_background</item>
</style>
I played around a bit with other possibilities but using a 9 patch with fixed margins and found out that the layer-list drawable is allowing to define offsets, hence margins around its enclosed drawables, so this worked for me:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:drawable="#drawable/my_custom_background"
android:top="5dp" android:bottom="5dp" android:left="5dp" android:right="5dp">
</item>
</layer-list>
and then you can use this as the "android:windowBackground":
<style name="ActivityDialog" parent="#android:style/Theme.Dialog">
<item name="android:windowBackground">#drawable/my_custom_layer_background</item>
</style>
Another option
Resources\Values\styles.xml
<style name="MessageDialog" parent="android:Theme.Holo.Light.Dialog">
<item name="android:windowBackground">#android:color/transparent</item>
</style>
where
AlertDialog.Builder builder = new AlertDialog.Builder(Activity, Resource.Style.MessageDialog);
These statements are excerpted from the following snippet:
public class MessageAlertDialog : DialogFragment, IDialogInterfaceOnClickListener
{
private const string DIALOG_TITLE = "dialogTitle";
private const string MESSAGE_TEXT = "messageText";
private const string MESSAGE_RESOURCE_ID = "messageResourceId";
private string _dialogTitle;
private string _messageText;
private int _messageResourceId;
public EventHandler OkClickEventHandler { get; set; }
public static MessageAlertDialog NewInstance(string messageText)
{
MessageAlertDialog dialogFragment = new MessageAlertDialog();
Bundle args = new Bundle();
args.PutString(MESSAGE_TEXT, messageText);
dialogFragment.Arguments = args;
return dialogFragment;
}
public static MessageAlertDialog NewInstance(string dialogTitle, string messageText)
{
MessageAlertDialog dialogFragment = new MessageAlertDialog();
Bundle args = new Bundle();
args.PutString(DIALOG_TITLE, dialogTitle);
args.PutString(MESSAGE_TEXT, messageText);
dialogFragment.Arguments = args;
return dialogFragment;
}
public static MessageAlertDialog NewInstance(int messageResourceId)
{
MessageAlertDialog dialogFragment = new MessageAlertDialog();
Bundle args = new Bundle();
args.PutInt(MESSAGE_RESOURCE_ID, messageResourceId);
dialogFragment.Arguments = args;
return dialogFragment;
}
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
_dialogTitle = Arguments.GetString(DIALOG_TITLE);
_messageText = Arguments.GetString(MESSAGE_TEXT);
_messageResourceId = Arguments.GetInt(MESSAGE_RESOURCE_ID);
}
public override Dialog OnCreateDialog(Bundle savedInstanceState)
{
base.OnCreateDialog(savedInstanceState);
AlertDialog.Builder builder = new AlertDialog.Builder(Activity, Resource.Style.MessageDialog);
if (_dialogTitle != null)
{
builder.SetTitle(_dialogTitle);
}
if (_messageText != null)
{
builder.SetMessage(_messageText);
}
else
{
View messageView = GetMessageView();
if (messageView != null)
{
builder.SetView(messageView);
}
}
builder.SetPositiveButton("OK", this);
//.SetCancelable(false);
this.Cancelable = false;
AlertDialog dialog = builder.Create();
dialog.SetCanceledOnTouchOutside(false);
//dialog.Window.SetBackgroundDrawableResource(Android.Resource.Color.Transparent);
return dialog;
}
private View GetMessageView()
{
if (_messageResourceId != 0)
{
View messageView = Activity.LayoutInflater.Inflate(_messageResourceId, null);
return messageView;
}
return null;
}
void IDialogInterfaceOnClickListener.OnClick(IDialogInterface di, int i)
{
OkClickEventHandler?.Invoke(this, null);
}
}
Usage
public static void ShowMessageAlertDialog(FragmentManager fragmentManager, string dialogTitle, string messageText, EventHandler okClickEventHandler)
{
MessageAlertDialog msgAlertDialog = MessageAlertDialog.NewInstance(dialogTitle, messageText);
msgAlertDialog.OkClickEventHandler += okClickEventHandler;
msgAlertDialog.Show(fragmentManager, "message_alert_dialog");
}
Another solution to this issue is to use android.support.v7.app.AlerDialog instead of android.app.AlertDialog. It's the most easiest and time effective solution. Design you custom view in the layout and then use it with your support package's AlertDialogBuilderclass and it will work like charm.
Can I change the background color of a Menu item in Android?
Please let me know if anyone have any solution to this. The last option will be obviously to customize it but is there any way for changing the text color without customizing it.
One simple line in your theme :)
<item name="android:actionMenuTextColor">#color/your_color</item>
It seems that an
<item name="android:itemTextAppearance">#style/myCustomMenuTextAppearance</item>
in my theme and
<style name="myCustomMenuTextAppearance" parent="#android:style/TextAppearance.Widget.IconMenu.Item">
<item name="android:textColor">#android:color/primary_text_dark</item>
</style>
in styles.xml change the style of list-items but not menu items.
You can change the color of the MenuItem text easily by using SpannableString instead of String.
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.your_menu, menu);
int positionOfMenuItem = 0; // or whatever...
MenuItem item = menu.getItem(positionOfMenuItem);
SpannableString s = new SpannableString("My red MenuItem");
s.setSpan(new ForegroundColorSpan(Color.RED), 0, s.length(), 0);
item.setTitle(s);
}
If you are using the new Toolbar, with the theme Theme.AppCompat.Light.NoActionBar, you can style it in the following way.
<style name="ToolbarTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:textColorPrimary">#color/my_color1</item>
<item name="android:textColorSecondary">#color/my_color2</item>
<item name="android:textColor">#color/my_color3</item>
</style>`
According to the results I got,
android:textColorPrimary is the text color displaying the name of your activity, which is the primary text of the toolbar.
android:textColorSecondary is the text color for subtitle and more options (3 dot) button. (Yes, it changed its color according to this property!)
android:textColor is the color for all other text including the menu.
Finally set the theme to the Toolbar
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:theme="#style/ToolbarTheme"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:minHeight="?attr/actionBarSize"/>
I went about it programmatically like this:
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.changeip_card_menu, menu);
for(int i = 0; i < menu.size(); i++) {
MenuItem item = menu.getItem(i);
SpannableString spanString = new SpannableString(menu.getItem(i).getTitle().toString());
spanString.setSpan(new ForegroundColorSpan(Color.BLACK), 0, spanString.length(), 0); //fix the color to white
item.setTitle(spanString);
}
return true;
}
If you are using menu as <android.support.design.widget.NavigationView /> then just add below line in NavigationView :
app:itemTextColor="your color"
Also available colorTint for icon, it will override color for your icon as well. For that you have to add below line:
app:itemIconTint="your color"
Example:
<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:itemTextColor="#color/color_white"
app:itemIconTint="#color/color_white"
android:background="#color/colorPrimary"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header_main"
app:menu="#menu/activity_main_drawer"/>
Hope it will help you.
in Kotlin I wrote these extensions:
fun MenuItem.setTitleColor(color: Int) {
val hexColor = Integer.toHexString(color).toUpperCase().substring(2)
val html = "<font color='#$hexColor'>$title</font>"
this.title = html.parseAsHtml()
}
#Suppress("DEPRECATION")
fun String.parseAsHtml(): Spanned {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Html.fromHtml(this, Html.FROM_HTML_MODE_LEGACY)
} else {
Html.fromHtml(this)
}
}
and used like this:
menu.findItem(R.id.main_settings).setTitleColor(Color.RED)
as you can see in this question you should:
<item name="android:textColorPrimary">yourColor</item>
Above code changes the text color of the menu action items for API >= v21.
<item name="actionMenuTextColor">#android:color/holo_green_light</item>
Above is the code for API < v21
I used the html tag to change a single item's text colour when the menu item is inflated. Hope it would be helpful.
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
menu.findItem(R.id.main_settings).setTitle(Html.fromHtml("<font color='#ff3824'>Settings</font>"));
return true;
}
SIMPLEST way to make custom menu color for single toolbar, not for AppTheme
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay.MenuBlue">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"/>
</android.support.design.widget.AppBarLayout>
usual toolbar on styles.xml
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"/>
our custom toolbar style
<style name="AppTheme.AppBarOverlay.MenuBlue">
<item name="actionMenuTextColor">#color/blue</item>
</style>
I was using Material design and when the toolbar was on a small screen clicking the more options would show a blank white drop down box. To fix this I think added this to the main AppTheme:
<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
<item name="android:itemTextAppearance">#style/menuItem</item>
</style>
And then created a style where you set the textColor for the menu items to your desired colour.
<style name="menuItem" parent="Widget.AppCompat.TextView.SpinnerItem">
<item name="android:textColor">#color/black</item>
</style>
The parent name Widget.AppCompat.TextView.SpinnerItem I don't think that matters too much, it should still work.
to change menu item text color use below code
<style name="AppToolbar" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:itemTextAppearance">#style/menu_item_color</item>
</style>
where
<style name="menu_item_color">
<item name="android:textColor">#color/app_font_color</item>
</style>
The short answer is YES. lucky you!
To do so, you need to override some styles of the Android default styles :
First, look at the definition of the themes in Android :
<style name="Theme.IconMenu">
<!-- Menu/item attributes -->
<item name="android:itemTextAppearance">#android:style/TextAppearance.Widget.IconMenu.Item</item>
<item name="android:itemBackground">#android:drawable/menu_selector</item>
<item name="android:itemIconDisabledAlpha">?android:attr/disabledAlpha</item>
<item name="android:horizontalDivider">#android:drawable/divider_horizontal_bright</item>
<item name="android:verticalDivider">#android:drawable/divider_vertical_bright</item>
<item name="android:windowAnimationStyle">#android:style/Animation.OptionsPanel</item>
<item name="android:moreIcon">#android:drawable/ic_menu_more</item>
<item name="android:background">#null</item>
</style>
So, the appearance of the text in the menu is in #android:style/TextAppearance.Widget.IconMenu.Item
Now, in the definition of the styles :
<style name="TextAppearance.Widget.IconMenu.Item" parent="TextAppearance.Small">
<item name="android:textColor">?textColorPrimaryInverse</item>
</style>
So now we have the name of the color in question, if you look in the color folder of the resources of the system :
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false" android:color="#android:color/bright_foreground_light_disabled" />
<item android:state_window_focused="false" android:color="#android:color/bright_foreground_light" />
<item android:state_pressed="true" android:color="#android:color/bright_foreground_light" />
<item android:state_selected="true" android:color="#android:color/bright_foreground_light" />
<item android:color="#android:color/bright_foreground_light" />
<!-- not selected -->
</selector>
Finally, here is what you need to do :
Override "TextAppearance.Widget.IconMenu.Item" and create your own style. Then link it to your own selector to make it the way you want.
Hope this helps you.
Good luck!
Options menu in android can be customized to set the background or change the text appearance. The background and text color in the menu couldn’t be changed using themes and styles. The android source code (data\res\layout\icon_menu_item_layout.xml)uses a custom item of class “com.android.internal.view.menu.IconMenuItem”View for the menu layout. We can make changes in the above class to customize the menu. To achieve the same, use LayoutInflater factory class and set the background and text color for the view.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.my_menu, menu);
getLayoutInflater().setFactory(new Factory() {
#Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
if (name .equalsIgnoreCase(“com.android.internal.view.menu.IconMenuItemView”)) {
try{
LayoutInflater f = getLayoutInflater();
final View view = f.createView(name, null, attrs);
new Handler().post(new Runnable() {
public void run() {
// set the background drawable
view .setBackgroundResource(R.drawable.my_ac_menu_background);
// set the text color
((TextView) view).setTextColor(Color.WHITE);
}
});
return view;
} catch (InflateException e) {
} catch (ClassNotFoundException e) {}
}
return null;
}
});
return super.onCreateOptionsMenu(menu);
}
Thanks for the code example.
I had to modify it go get it to work with a context menu.
This is my solution.
static final Class<?>[] constructorSignature = new Class[] {Context.class, AttributeSet.class};
class MenuColorFix implements LayoutInflater.Factory {
public View onCreateView(String name, Context context, AttributeSet attrs) {
if (name.equalsIgnoreCase("com.android.internal.view.menu.ListMenuItemView")) {
try {
Class<? extends ViewGroup> clazz = context.getClassLoader().loadClass(name).asSubclass(ViewGroup.class);
Constructor<? extends ViewGroup> constructor = clazz.getConstructor(constructorSignature);
final ViewGroup view = constructor.newInstance(new Object[]{context,attrs});
new Handler().post(new Runnable() {
public void run() {
try {
view.setBackgroundColor(Color.BLACK);
List<View> children = getAllChildren(view);
for(int i = 0; i< children.size(); i++) {
View child = children.get(i);
if ( child instanceof TextView ) {
((TextView)child).setTextColor(Color.WHITE);
}
}
}
catch (Exception e) {
Log.i(TAG, "Caught Exception!",e);
}
}
});
return view;
}
catch (Exception e) {
Log.i(TAG, "Caught Exception!",e);
}
}
return null;
}
}
public List<View> getAllChildren(ViewGroup vg) {
ArrayList<View> result = new ArrayList<View>();
for ( int i = 0; i < vg.getChildCount(); i++ ) {
View child = vg.getChildAt(i);
if ( child instanceof ViewGroup) {
result.addAll(getAllChildren((ViewGroup)child));
}
else {
result.add(child);
}
}
return result;
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
LayoutInflater lInflater = getLayoutInflater();
if ( lInflater.getFactory() == null ) {
lInflater.setFactory(new MenuColorFix());
}
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.myMenu, menu);
}
For me this works with Android 1.6, 2.03 and 4.03.
i found it Eureka !!
in your app theme:
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:actionBarStyle">#style/ActionBarTheme</item>
<!-- backward compatibility -->
<item name="actionBarStyle">#style/ActionBarTheme</item>
</style>
here is your action bar theme:
<style name="ActionBarTheme" parent="#style/Widget.AppCompat.Light.ActionBar.Solid.Inverse">
<item name="android:background">#color/actionbar_bg_color</item>
<item name="popupTheme">#style/ActionBarPopupTheme</item
<!-- backward compatibility -->
<item name="background">#color/actionbar_bg_color</item>
</style>
and here is your popup theme:
<style name="ActionBarPopupTheme">
<item name="android:textColor">#color/menu_text_color</item>
<item name="android:background">#color/menu_bg_color</item>
</style>
Cheers ;)
Simply add this to your theme
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:itemTextAppearance">#style/AppTheme.ItemTextStyle</item>
</style>
<style name="AppTheme.ItemTextStyle" parent="#android:style/TextAppearance.Widget.IconMenu.Item">
<item name="android:textColor">#color/orange_500</item>
</style>
Tested on API 21
Thanks to max.musterman, this is the solution I got to work in level 22:
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
MenuItem searchMenuItem = menu.findItem(R.id.search);
SearchView searchView = (SearchView) searchMenuItem.getActionView();
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
searchView.setSubmitButtonEnabled(true);
searchView.setOnQueryTextListener(this);
setMenuTextColor(menu, R.id.displaySummary, R.string.show_summary);
setMenuTextColor(menu, R.id.about, R.string.text_about);
setMenuTextColor(menu, R.id.importExport, R.string.import_export);
setMenuTextColor(menu, R.id.preferences, R.string.settings);
return true;
}
private void setMenuTextColor(Menu menu, int menuResource, int menuTextResource) {
MenuItem item = menu.findItem(menuResource);
SpannableString s = new SpannableString(getString(menuTextResource));
s.setSpan(new ForegroundColorSpan(Color.BLACK), 0, s.length(), 0);
item.setTitle(s);
}
The hardcoded Color.BLACK could become an additional parameter to the setMenuTextColor method. Also, I only used this for menu items which were android:showAsAction="never".
Adding this into my styles.xml worked for me
<item name="android:textColorPrimary">?android:attr/textColorPrimaryInverse</item>
You can set color programmatically.
private static void setMenuTextColor(final Context context, final Toolbar toolbar, final int menuResId, final int colorRes) {
toolbar.post(new Runnable() {
#Override
public void run() {
View settingsMenuItem = toolbar.findViewById(menuResId);
if (settingsMenuItem instanceof TextView) {
if (DEBUG) {
Log.i(TAG, "setMenuTextColor textview");
}
TextView tv = (TextView) settingsMenuItem;
tv.setTextColor(ContextCompat.getColor(context, colorRes));
} else { // you can ignore this branch, because usually there is not the situation
Menu menu = toolbar.getMenu();
MenuItem item = menu.findItem(menuResId);
SpannableString s = new SpannableString(item.getTitle());
s.setSpan(new ForegroundColorSpan(ContextCompat.getColor(context, colorRes)), 0, s.length(), 0);
item.setTitle(s);
}
}
});
}
If you want to set color for an individual menu item, customizing a toolbar theme is not the right solution. To achieve this, you can make use of android:actionLayout and an action view for the menu item.
First create an XML layout file for the action view. In this example we use a button as an action view:
menu_button.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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">
<Button
android:id="#+id/menuButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Done"
android:textColor="?android:attr/colorAccent"
style="?android:attr/buttonBarButtonStyle"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
In the code snippet above, we use android:textColor="?android:attr/colorAccent" to customize button text color.
Then in your XML layout file for the menu, include app:actionLayout="#layout/menu_button" as shown below:
main_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/menuItem"
android:title=""
app:actionLayout="#layout/menu_button"
app:showAsAction="always"/>
</menu>
Last override the onCreateOptionsMenu() method in your activity:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu, menu);
MenuItem item = menu.findItem(R.id.menuItem);
Button saveButton = item.getActionView().findViewById(R.id.menuButton);
saveButton.setOnClickListener(view -> {
// Do something
});
return true;
}
...or fragment:
#Override
public void onCreateOptionsMenu(#NonNull Menu menu, #NonNull MenuInflater inflater){
inflater.inflate(R.menu.main_menu, menu);
MenuItem item = menu.findItem(R.id.menuItem);
Button saveButton = item.getActionView().findViewById(R.id.menuButton);
button.setOnClickListener(view -> {
// Do something
});
}
For more details on action views, see the Android developer guide.
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.search, menu);
MenuItem myActionMenuItem = menu.findItem( R.id.action_search);
SearchView searchView = (SearchView) myActionMenuItem.getActionView();
EditText searchEditText = (EditText) searchView.findViewById(android.support.v7.appcompat.R.id.search_src_text);
searchEditText.setTextColor(Color.WHITE); //You color here
My situation was settings text color in the options menu (main app menu showed on menu button press).
Tested in API 16 with appcompat-v7-27.0.2 library, AppCompatActivity for MainActivity and AppCompat theme for the application in AndroidManifest.xml.
styles.xml:
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="actionBarPopupTheme">#style/PopupTheme</item>
</style>
<style name="PopupTheme" parent="#style/ThemeOverlay.AppCompat.Light">
<item name="android:textColorSecondary">#f00</item>
</style>
Don't know if that textColorSecondary affects other elements but it controls the menu text color.
I searched some examples on the topic but all ready-to-use snippets didn't work.
So I wanted to investigate it with the source code for the appcompat-v7 library (specifically with the res folder of the .aar package).
Though in my case I used Eclipse with exploded .aar dependencies. So I could change the default styles and check the results. Don't know how to explode the libraries to use with Gradle or Android Studio directly. It deserves another thread of investigation.
So my purpose was so find which color in the res/values/values.xml file is used for the menu text (I was almost sure the color was there).
I opened that file, then duplicated all colors, put them below the default ones to override them and assigned #f00 value to all of them.
Start the app.
Many elements had red background or text color. And the menu items too. That was what I needed.
Removing my added colors by blocks of 5-10 lines I ended with the secondary_text_default_material_light color item.
Searching that name in the files within the res folder (or better within res/colors) I found only one occurrence in the color/abc_secondary_text_material_light.xml file (I used Sublime Text for these operations so it's easier to find thing I need).
Back to the values.xml 8 usages were found for the #color/abc_secondary_text_material_light.
It was a Light theme so 4 left in 2 themes: Base.ThemeOverlay.AppCompat.Light and Platform.AppCompat.Light.
The first theme was a child of the second one so there were only 2 attributes with that color resource: android:textColorSecondary and android:textColorTertiaryin the Base.ThemeOverlay.AppCompat.Light.
Changing their values directly in the values.xml and running the app I found that the final correct attribute was android:textColorSecondary.
Next I needed a theme or another attribute so I could change it in my app's style.xml (because my theme had as the parent the Theme.AppCompat.Light and not the ThemeOverlay.AppCompat.Light).
I searched in the same file for the Base.ThemeOverlay.AppCompat.Light. It had a child ThemeOverlay.AppCompat.Light.
Searching for the ThemeOverlay.AppCompat.Light I found its usage in the Base.Theme.AppCompat.Light.DarkActionBar theme as the actionBarPopupTheme attribute value.
My app's theme Theme.AppCompat.Light.DarkActionBar was a child of the found Base.Theme.AppCompat.Light.DarkActionBar so I could use that attribute in my styles.xml without problems.
As it's seen in the example code above I created a child theme from the mentioned ThemeOverlay.AppCompat.Light and changed the android:textColorSecondary attribute.
Sephy's solution doesn't work. It's possible to override the options menu item text appearance using the method described above, but not the item or menu. To do that there are essentially 3 ways:
How to change the background color of the options menu?
Write your own view to display and override onCreateOptionsMenu and onPrepareOptionsMenu to get the results you want. I state this generally because you can generally do whatever you want in these methods, but you probably won't want to call into super().
Copy code from the open-source SDK and customize for your behavior. The default menu implementation used by Activity will no longer apply.
See Issue 4441: Custom Options Menu Theme for more clues.
try this code....
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.my_menu, menu);
getLayoutInflater().setFactory(new Factory() {
#Override
public View onCreateView(String name, Context context,
AttributeSet attrs) {
if (name.equalsIgnoreCase("com.android.internal.view.menu.IconMenuItemView")) {
try {
LayoutInflater f = getLayoutInflater();
final View view = f.createView(name, null, attrs);
new Handler().post(new Runnable() {
public void run() {
// set the background drawable
view.setBackgroundResource(R.drawable.my_ac_menu_background);
// set the text color
((TextView) view).setTextColor(Color.WHITE);
}
});
return view;
} catch (InflateException e) {
} catch (ClassNotFoundException e) {
}
}
return null;
}
});
return super.onCreateOptionsMenu(menu);
}
Add textColor as below
<style name="MyTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light">
<item name="android:textColor">#color/radio_color_gray</item>
</style>
and use it in Toolbar in xml file
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:popupTheme="#style/MyTheme.PopupOverlay" />
This is how you can color a specific menu item with color, works for all API levels:
public static void setToolbarMenuItemTextColor(final Toolbar toolbar,
final #ColorRes int color,
#IdRes final int resId) {
if (toolbar != null) {
for (int i = 0; i < toolbar.getChildCount(); i++) {
final View view = toolbar.getChildAt(i);
if (view instanceof ActionMenuView) {
final ActionMenuView actionMenuView = (ActionMenuView) view;
// view children are accessible only after layout-ing
actionMenuView.post(new Runnable() {
#Override
public void run() {
for (int j = 0; j < actionMenuView.getChildCount(); j++) {
final View innerView = actionMenuView.getChildAt(j);
if (innerView instanceof ActionMenuItemView) {
final ActionMenuItemView itemView = (ActionMenuItemView) innerView;
if (resId == itemView.getId()) {
itemView.setTextColor(ContextCompat.getColor(toolbar.getContext(), color));
}
}
}
}
});
}
}
}
}
By doing that you loose the background selector effect, so here is the code to apply a custom background selector to all of the menu item children.
public static void setToolbarMenuItemsBackgroundSelector(final Context context,
final Toolbar toolbar) {
if (toolbar != null) {
for (int i = 0; i < toolbar.getChildCount(); i++) {
final View view = toolbar.getChildAt(i);
if (view instanceof ImageButton) {
// left toolbar icon (navigation, hamburger, ...)
UiHelper.setViewBackgroundSelector(context, view);
} else if (view instanceof ActionMenuView) {
final ActionMenuView actionMenuView = (ActionMenuView) view;
// view children are accessible only after layout-ing
actionMenuView.post(new Runnable() {
#Override
public void run() {
for (int j = 0; j < actionMenuView.getChildCount(); j++) {
final View innerView = actionMenuView.getChildAt(j);
if (innerView instanceof ActionMenuItemView) {
// text item views
final ActionMenuItemView itemView = (ActionMenuItemView) innerView;
UiHelper.setViewBackgroundSelector(context, itemView);
// icon item views
for (int k = 0; k < itemView.getCompoundDrawables().length; k++) {
if (itemView.getCompoundDrawables()[k] != null) {
UiHelper.setViewBackgroundSelector(context, itemView);
}
}
}
}
}
});
}
}
}
}
Here is the helper function also:
public static void setViewBackgroundSelector(#NonNull Context context, #NonNull View itemView) {
int[] attrs = new int[]{R.attr.selectableItemBackgroundBorderless};
TypedArray ta = context.obtainStyledAttributes(attrs);
Drawable drawable = ta.getDrawable(0);
ta.recycle();
ViewCompat.setBackground(itemView, drawable);
}
For changing the text color, you can just set a custom view for the MenuItem, and then you can define the color for the text.
Sample Code : MenuItem.setActionView()
Simply just go to
Values - styles and inside styles and type
your color