I have this function that works fine on Android 4.4.1, but breaks on 5.0+.
public static SpannableStringBuilder prependImage(Drawable drawable, String text) {
SpannableStringBuilder builder = new SpannableStringBuilder(" " + text);
builder.setSpan(new ImageSpan(drawable), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
return builder;
}
And I use it like this:
class MyButton extends Button {
// ... snip ...
setText(
prependImage(
getDrawable(imageResource, color),
getContext().getString(stringResource)),
BufferType.SPANNABLE);
Here is the getDrawable() method referenced above:
private Drawable getDrawable(int resource, int color) {
final Resources resources = getContext().getResources();
Drawable drawable = resources.getDrawable(resource);
if (drawable != null) {
drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
}
return drawable;
}
When I debug, everything seems to succeed, but no image is drawn. Any ideas what I might be doing wrong?
By default, in Material buttons are styled to show text in all-caps. However, there is a bug in the AllCapsTransformationMethod used for capitalization that causes it to discard Spannable data.
You can override the default button styling and disable all-caps by specifying android:textAllCaps="false" on your Button.
<Button
...
android:textAllCaps="false" />
have a look here
Your code related to working with Spannables is ok. You can check it by setting text for TextView.
The problem is in material design of button on Android 5.0.
<style name="Widget.Material.Button">
<item name="background">#drawable/btn_default_material</item>
<item name="textAppearance">?attr/textAppearanceButton</item>
<item name="minHeight">48dip</item>
<item name="minWidth">88dip</item>
<item name="stateListAnimator">#anim/button_state_list_anim_material</item>
<item name="focusable">true</item>
<item name="clickable">true</item>
<item name="gravity">center_vertical|center_horizontal</item>
</style>
There are two solution.
The first one is just use TextView as your button and setText with image to it.
For another (and may be more correct) you need to extend button style (Widget.Material.Button) in next way:
<style name="BtnStyle" parent="android:Widget.Material.Button">
<item name="android:textAppearance">#null</item>
</style>
Then in your layout:
<Button
android:id="#+id/test2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Test"
style="#style/BtnStyle"/>
After you'll do it you should see the images in the button.
Don't forget for Android version that is lower than 5.0 you should create BtnStyle too, but in other resource directory (res/values-v14/style.xml).
One thing to note, drawable vectors won't work, you must either have a drawable which is a png or jpeg or pass to ImageSpan bitmap instead
Maybe you need to check the content of that Drawable object, you use the getDrawable() to get the Drawable object, but the API definition seems not match your calling parameters.
For Android 5.0+
Drawable getDrawable(int id) This method was deprecated in API level
22. Use getDrawable(int, Theme) instead.
Drawable getDrawable(int id, Resources.Theme theme) Return a drawable
object associated with a particular resource ID and styled for the
specified theme.
The second parameter looks like to be a Theme, not a color. right ?
try this
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getResources().getDrawable(R.drawable.your_drawable, getTheme());
} else {
getResources().
getDrawable(R.drawable.your_drawable);
}
Related
I want to show the "x" button instead of the default back arrow as the "home" button on toolbar. I have searched how to use a custom image and it works and I have searched how to use a specific color for the back arrow and it works. The problem is, when I put both the custom image and the custom color, it shows the image with its default color, black, when I want it to be blue.
This is the xml for the toolbar:
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:id="#+id/toolbar"
android:theme="#style/ThemeToolbar">
And this is the ThemeToolbar style:
<style name="ThemeToolbarDetails" parent="Theme.AppCompat.Light">
<item name="colorControlNormal">#color/blue</item>
<item name="homeAsUpIndicator">#drawable/close</item>
</style>
I have tried colorControlNormal, android:textColorSecondary but none of this works when using a custom image.
First of all, keep this line on your style: <item name="homeAsUpIndicator">#drawable/close</item>.
Then, you have a couple of ways of solving the color part.
Option 1: If you're working with Vector Drawables, it's easier to just change the color inside the XML file.
Option 2: Alternatively, you can also programmatically tint any menu item. Get the Menu object in the onCreateOptionsMenu() method, and then try the snippet below:
private void tintIcon(#NonNull MenuItem item, int color) {
Drawable drawable = item.getIcon();
if (drawable != null) {
final Drawable wrapped = DrawableCompat.wrap(drawable);
drawable.mutate();
DrawableCompat.setTint(wrapped, color);
item.setIcon(drawable);
}
}
Option 3: Change the drawable and the color programatically.
final Drawable myIcon = ContextCompat.getDrawable(context, R.drawable.your_icon);
myIcon.setColorFilter(ContextCompat.getColor(context, R.color.your_color), PorterDuff.Mode.SRC_ATOP);
getSupportActionBar().setHomeAsUpIndicator(myIcon);
I found various answers on how to change the line color of an EditText in Android programatically.
Right now I'm using this solution:
final Drawable originalDrawable = editText.getBackground();
final Drawable wrappedDrawable = DrawableCompat.wrap(originalDrawable);
DrawableCompat.setTintList(wrappedDrawable, ColorStateList.valueOf(darkVibrantColor));
editText.setBackground(wrappedDrawable);
This does in fact change to color of an EditText, but unfortunately it does not only change the line color of the specific EditText I'm using but the line color of all EditTexts used in my application. Event if they are in different activities.
How do I change the line color of just one specific EditText without changing the line color globally? Thanks.
Update: I cannot use a predefined style as the color is generated dynamically while the application is running.
Try this, could help you
In your style.xml
<style name="MyEditText" parent="Theme.AppCompat.Light">
<item name="colorControlNormal">#color/indigo</item>
<item name="colorControlActivated">#color/pink</item>
<item name="android:padding">20dp</item>
<item name="android:textSize">16dp>
<item name="android:editTextColor">#color/black</item>
<item name="android:tint">#color/colorPrimary</item>
</style>
in you edittext add your style
<EditText
style="#style/MyEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Subject"/>
I have provided code to programmatically change underline color of EditText.
EditText editTextOne=(EditText) findViewById(R.id.edit_text_one);
Drawable drawable=editTextOne.getBackground();
int color=Color.parseColor("#FFFFFF");
drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
if (Build.VERSION.SDK_INT > 16) {
editTextOne.setBackground(drawable);
} else {
editTextOne.setCompoundDrawables(null,null,drawable,null);
}
I found the solution. It's posted in this (not accepted) answer. The trick is to mutate the background drawable after it is retrieved from the EditText.
Here's my working code:
final Drawable originalDrawable = editText.getBackground();
originalDrawable.mutate();
final Drawable wrappedDrawable = DrawableCompat.wrap(originalDrawable);
DrawableCompat.setTintList(wrappedDrawable, ColorStateList.valueOf(darkVibrantColor));
editText.setBackground(wrappedDrawable);
I am using appcompat v7 to get the look consistent on Android 5 and less. It works rather well. However I cannot figure out how to change the bottom line color and the accent color for EditTexts. Is it possible?
I have tried to define a custom android:editTextStyle (cf. below) but I only succeeded to change the full background color or text color but not the bottom line nor the accent color. Is there a specific property value to use? do I have to use a custom drawable image through the android:background property? is it not possible to specify a color in hexa?
<style name="Theme.App.Base" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:editTextStyle">#style/Widget.App.EditText</item>
</style>
<style name="Widget.App.EditText" parent="Widget.AppCompat.EditText">
???
</style>
According to android API 21 sources, EditTexts with material design seem to use colorControlActivated and colorControlNormal. Therefore, I have tried to override these properties in the previous style definition but it has no effect. Probably appcompat does not use it. Unfortunately, I cannot find the sources for the last version of appcompat with material design.
Finally, I have found a solution. It simply consists of overriding the value for colorControlActivated, colorControlHighlight and colorControlNormal in your app theme definition and not your edittext style. Then, think to use this theme for whatever activity you desire. Below is an example:
<style name="Theme.App.Base" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorControlNormal">#c5c5c5</item>
<item name="colorControlActivated">#color/accent</item>
<item name="colorControlHighlight">#color/accent</item>
</style>
I felt like this needed an answer in case somebody wanted to change just a single edittext. I do it like this:
editText.getBackground().mutate().setColorFilter(ContextCompat.getColor(context, R.color.your_color), PorterDuff.Mode.SRC_ATOP);
While Laurents solution is correct, it comes with some drawbacks as described in the comments since not only the bottom line of the EditText gets tinted but the Back Button of the Toolbar, CheckBoxes etc. as well.
Luckily v22.1 of appcompat-v7 introduced some new possibilities. Now it's possible to assign a specific theme only to one view. Straight from the Changelog:
Deprecated use of app:theme for styling Toolbar. You can now use android:theme for toolbars on all API level 7 and higher devices and android:theme support for all widgets on API level 11 and higher devices.
So instead of setting the desired color in a global theme, we create a new one and assign it only to the EditText.
Example:
<style name="MyEditTextTheme">
<!-- Used for the bottom line when not selected / focused -->
<item name="colorControlNormal">#9e9e9e</item>
<!-- colorControlActivated & colorControlHighlight use the colorAccent color by default -->
</style>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/MyEditTextTheme"/>
This can be changed in XML by using:
For Reference API >= 21 compatibility use:
android:backgroundTint="#color/blue"
For backward API < 21 compatibility use:
app:backgroundTint="#color/blue"
Here is the solution for API < 21 and above
Drawable drawable = yourEditText.getBackground(); // get current EditText drawable
drawable.setColorFilter(Color.GREEN, PorterDuff.Mode.SRC_ATOP); // change the drawable color
if(Build.VERSION.SDK_INT > 16) {
yourEditText.setBackground(drawable); // set the new drawable to EditText
}else{
yourEditText.setBackgroundDrawable(drawable); // use setBackgroundDrawable because setBackground required API 16
}
Hope it help
The accepted answer is a bit more per style basis thing, but the most efficient thing to do is to add the colorAccent attribute in your AppTheme style like this:
<style name="AppTheme.Base" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorAccent">#color/colorAccent</item>
<item name="android:editTextStyle">#style/EditTextStyle</item>
</style>
<style name="EditTextStyle" parent="Widget.AppCompat.EditText"/>
The colorAccent attribute is used for widget tinting throughout the app and thus should be used for consistency
If you are using appcompat-v7:22.1.0+ you can use the DrawableCompat to tint your widgets
public static void tintWidget(View view, int color) {
Drawable wrappedDrawable = DrawableCompat.wrap(view.getBackground());
DrawableCompat.setTint(wrappedDrawable.mutate(), getResources().getColor(color));
view.setBackgroundDrawable(wrappedDrawable);
}
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
<item name="colorControlNormal">#color/colorAccent</item>
<item name="colorControlActivated">#color/colorAccent</item>
<item name="colorControlHighlight">#color/colorAccent</item>
</style>
Use:
<EditText
app:backgroundTint="#color/blue"/>
This will support pre-Lollipop devices not only +21
One quick solution for your problem is to look in yourappspackage/build/intermediates/exploded-aar/com.android.support/appcompat-v7/res/drawable/ for abc_edit_text_material.xml and copy that xml file in your drawable folder. Then you can change the colour of the 9 patch files from inside this selector, in order to match your preferences.
It's very easy just add android:backgroundTint attribute in your EditText.
android:backgroundTint="#color/blue"
android:backgroundTint="#ffffff"
android:backgroundTint="#color/red"
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="#ffffff"/>
Here is a part of source code of TextInputLayout in support design library(UPDATED for version 23.2.0), which changes EditText's bottom line color in a simpler way:
private void updateEditTextBackground() {
ensureBackgroundDrawableStateWorkaround();
final Drawable editTextBackground = mEditText.getBackground();
if (editTextBackground == null) {
return;
}
if (mErrorShown && mErrorView != null) {
// Set a color filter of the error color
editTextBackground.setColorFilter(
AppCompatDrawableManager.getPorterDuffColorFilter(
mErrorView.getCurrentTextColor(), PorterDuff.Mode.SRC_IN));
}
...
}
It seems that all of above code become useless right now in 23.2.0 if you want to change the color programatically.
And if you want to support all platforms, here is my method:
/**
* Set backgroundTint to {#link View} across all targeting platform level.
* #param view the {#link View} to tint.
* #param color color used to tint.
*/
public static void tintView(View view, int color) {
final Drawable d = view.getBackground();
final Drawable nd = d.getConstantState().newDrawable();
nd.setColorFilter(AppCompatDrawableManager.getPorterDuffColorFilter(
color, PorterDuff.Mode.SRC_IN));
view.setBackground(nd);
}
I too was stuck on this problem for too long.
I required a solution that worked for versions both above and below v21.
I finally discovered a very simple perhaps not ideal but effective solution: Simply set the background colour to transparent in the EditText properties.
<EditText
android:background="#android:color/transparent"/>
I hope this saves someone some time.
For me I modified both the AppTheme and a value colors.xml Both the colorControlNormal and the colorAccent helped me change the EditText border color. As well as the cursor, and the "|" when inside an EditText.
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorControlNormal">#color/yellow</item>
<item name="colorAccent">#color/yellow</item>
</style>
Here is the colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="yellow">#B7EC2A</color>
</resources>
I took out the android:textCursorDrawable attribute to #null that I placed inside the editText style. When I tried using this, the colors would not change.
You can set background of edittext to a rectangle with minus padding on left, right and top to achieve this. Here is the xml example:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:top="-1dp"
android:left="-1dp"
android:right="-1dp"
android:bottom="1dp"
>
<shape android:shape="rectangle">
<stroke android:width="1dp" android:color="#6A9A3A"/>
</shape>
</item>
</layer-list>
Replace the shape with a selector if you want to provide different width and color for focused edittext.
I worked out a working solution to this problem after 2 days of struggle, below solution is perfect for them who want to change few edit text only, change/toggle color through java code, and want to overcome the problems of different behavior on OS versions due to use setColorFilter() method.
import android.content.Context;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.AppCompatDrawableManager;
import android.support.v7.widget.AppCompatEditText;
import android.util.AttributeSet;
import com.newco.cooltv.R;
public class RqubeErrorEditText extends AppCompatEditText {
private int errorUnderlineColor;
private boolean isErrorStateEnabled;
private boolean mHasReconstructedEditTextBackground;
public RqubeErrorEditText(Context context) {
super(context);
initColors();
}
public RqubeErrorEditText(Context context, AttributeSet attrs) {
super(context, attrs);
initColors();
}
public RqubeErrorEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initColors();
}
private void initColors() {
errorUnderlineColor = R.color.et_error_color_rule;
}
public void setErrorColor() {
ensureBackgroundDrawableStateWorkaround();
getBackground().setColorFilter(AppCompatDrawableManager.getPorterDuffColorFilter(
ContextCompat.getColor(getContext(), errorUnderlineColor), PorterDuff.Mode.SRC_IN));
}
private void ensureBackgroundDrawableStateWorkaround() {
final Drawable bg = getBackground();
if (bg == null) {
return;
}
if (!mHasReconstructedEditTextBackground) {
// This is gross. There is an issue in the platform which affects container Drawables
// where the first drawable retrieved from resources will propogate any changes
// (like color filter) to all instances from the cache. We'll try to workaround it...
final Drawable newBg = bg.getConstantState().newDrawable();
//if (bg instanceof DrawableContainer) {
// // If we have a Drawable container, we can try and set it's constant state via
// // reflection from the new Drawable
// mHasReconstructedEditTextBackground =
// DrawableUtils.setContainerConstantState(
// (DrawableContainer) bg, newBg.getConstantState());
//}
if (!mHasReconstructedEditTextBackground) {
// If we reach here then we just need to set a brand new instance of the Drawable
// as the background. This has the unfortunate side-effect of wiping out any
// user set padding, but I'd hope that use of custom padding on an EditText
// is limited.
setBackgroundDrawable(newBg);
mHasReconstructedEditTextBackground = true;
}
}
}
public boolean isErrorStateEnabled() {
return isErrorStateEnabled;
}
public void setErrorState(boolean isErrorStateEnabled) {
this.isErrorStateEnabled = isErrorStateEnabled;
if (isErrorStateEnabled) {
setErrorColor();
invalidate();
} else {
getBackground().mutate().clearColorFilter();
invalidate();
}
}
}
Uses in xml
<com.rqube.ui.widget.RqubeErrorEditText
android:id="#+id/f_signup_et_referral_code"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toEndOf="#+id/referral_iv"
android:layout_toRightOf="#+id/referral_iv"
android:ems="10"
android:hint="#string/lbl_referral_code"
android:imeOptions="actionNext"
android:inputType="textEmailAddress"
android:textSize="#dimen/text_size_sp_16"
android:theme="#style/EditTextStyle"/>
Add lines in style
<style name="EditTextStyle" parent="android:Widget.EditText">
<item name="android:textColor">#color/txt_color_change</item>
<item name="android:textColorHint">#color/et_default_color_text</item>
<item name="colorControlNormal">#color/et_default_color_rule</item>
<item name="colorControlActivated">#color/et_engagged_color_rule</item>
</style>
java code to toggle color
myRqubeEditText.setErrorState(true);
myRqubeEditText.setErrorState(false);
In Activit.XML add the code
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPersonName"
android:ems="10"
android:id="#+id/editText"
android:hint="Informe o usuário"
android:backgroundTint="#android:color/transparent"/>
Where BackgroundTint=color for your desired colour
I use this method to change the color of the line with PorterDuff, with no other drawable.
public void changeBottomColorSearchView(int color) {
int searchPlateId = mSearchView.getContext().getResources().getIdentifier("android:id/search_plate", null, null);
View searchPlate = mSearchView.findViewById(searchPlateId);
searchPlate.getBackground().setColorFilter(color, PorterDuff.Mode.SRC_IN);
}
If you want change bottom line without using app colors, use these lines in your theme:
<item name="android:editTextStyle">#android:style/Widget.EditText</item>
<item name="editTextStyle">#android:style/Widget.EditText</item>
I don't know another solution.
I was absolutely baffled by this problem. I had tried everything in this thread, and in others, but no matter what I did I could not change the color of the underline to anything other than the default blue.
I finally figured out what was going on. I was (incorrectly) using android.widget.EditText when making a new instance (but the rest of my components were from the appcompat library). I should have used android.support.v7.widget.AppCompatEditText. I replaced new EditText(this) with new AppCompatEditText(this)
and the problem was instantly solved. It turns out, if you are actually using AppCompatEditText, it will just respect the accentColor from your theme (as mentioned in several comments above) and no additional configuration is necessary.
This is the easiest and most efficient/reusable/works on all APIs
Create a custom EditText class like so:
public class EditText extends android.widget.EditText {
public EditText(Context context) {
super(context);
init();
}
public EditText(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public EditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
getBackground().mutate().setColorFilter(ContextCompat.getColor(getContext(), R.color.colorAccent), PorterDuff.Mode.SRC_ATOP);
}
}
Then use it like this:
<company.com.app.EditText
android:layout_width="200dp"
android:layout_height="wrap_content"/>
To change the EditText background dynamically, you can use ColorStateList.
int[][] states = new int[][] {
new int[] { android.R.attr.state_enabled}, // enabled
new int[] {-android.R.attr.state_enabled}, // disabled
new int[] {-android.R.attr.state_checked}, // unchecked
new int[] { android.R.attr.state_pressed} // pressed
};
int[] colors = new int[] {
Color.BLACK,
Color.RED,
Color.GREEN,
Color.BLUE
};
ColorStateList colorStateList = new ColorStateList(states, colors);
Credits: This SO answer about ColorStateList is awesome.
You can use just backgroundTint for change bottom line color of edit text
android:backgroundTint="#000000"
example :
<EditText
android:id="#+id/title1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="#000000" />
Add app:backgroundTint for below api level 21. Otherwise use android:backgroundTint.
For below api level 21.
<EditText
android:id="#+id/edt_name"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:textColor="#0012ff"
app:backgroundTint="#0012ff"/>
For higher than api level 21.
<EditText
android:id="#+id/edt_name"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:textColor="#0012ff"
android:backgroundTint="#0012ff"/>
Please modify this method according to your need. This worked for me!
private boolean validateMobilenumber() {
if (mobilenumber.getText().toString().trim().isEmpty() || mobilenumber.getText().toString().length() < 10) {
input_layout_mobilenumber.setErrorEnabled(true);
input_layout_mobilenumber.setError(getString(R.string.err_msg_mobilenumber));
// requestFocus(mobilenumber);
return false;
} else {
input_layout_mobilenumber.setError(null);
input_layout_mobilenumber.setErrorEnabled(false);
mobilenumber.setBackground(mobilenumber.getBackground().getConstantState().newDrawable());
}
}
I worked so hard to change the default background color of Lollipop's DatePicker. I cannot simply use Styleable attrs to change the default style. And as mentioned in another post, I can only use reflection to find the view, and then make changes on it.
e.g.
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
int monthDayYearLayoutId = Resources.getSystem().getIdentifier("date_picker_month_day_year_layout", "id", "android");
if (monthDayYearLayoutId != 0) {
View monthDayYearLayout = datePicker.findViewById(monthDayYearLayoutId);
if (monthDayYearLayout != null) {
monthDayYearLayout.setBackgroundColor(getResources().getColor(R.color.colorful));
}
}
}
However, I am only able to access the upper half of the DatePicker (see below).
DatePicker's upper half
However,for the lower half which is a CalendarView (see below), I cannot change using the same approach, as I cannot find the view (I tried to find the view by the id R.id.calendar_view, yet it is not working.).
DatePicker's lower half
To be precise, I would like to change the background color of the circled date, and the textColor for the present date (in this case, it is 7th March, 2014)
Any hints? Thanks a lot.
Updates:
After looking through the docs, I found that the lower half's calendar is in fact a SimpleMonthView.class, and the background color of the circle and the textColor for the present day are both governed by the param (int) mSelectedDayColor.
mSelectedDayColor = colors.getColorForState(ENABLED_SELECTED_STATE_SET,
res.getColor(R.color.holo_blue_light));
I cannot use the previous method, since the calendar is created in the onDraw method programmatically, but not by inflating a layout file.
So the problem boils down to - how could I change the resource value for mSelectedDayColor?
Thanks..
Updates:
After working on alanv's solution, I tried this:
Since I am working on Lollipop's DatePicker, I put the following in v21-styles.xml:
<style name="MyCalendarView" parent="#android:style/Widget.CalendarView">
<item name="android:showWeekNumber">true</item>
<item name="android:minDate">01/01/2016</item>
<item name="android:maxDate">12/31/2100</item>
<item name="android:shownWeekCount">6</item>
<item name="android:selectedWeekBackgroundColor">#330099FF</item>
<item name="android:focusedMonthDateColor">#FFFFFFFF</item>
<item name="android:unfocusedMonthDateColor">#66FFFFFF</item>
<item name="android:weekNumberColor">#33FFFFFF</item>
<item name="android:weekSeparatorLineColor">#19FFFFFF</item>
</style>
And I changed some of the default values, eg. android:minDate.
And in my activity_main.xml,
<DatePicker
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/date_picker"
android:layout_centerHorizontal="true"
android:theme="#style/MyCalendarView"/>
But there is no effect on DatePicker for Lollipop.
Any code using reflection may break on future OS updates. You should never use reflection to access private APIs or values.
The easiest way would be to create an overlay theme that redefines android:colorAccent and apply that to your DatePicker.
res/values/styles.xml:
<style name="MyThemeOverlay">
<item name="android:colorAccent">#color/my_accent</item>
</style>
res/layout/my_layout.xml:
<DatePicker
...
android:theme="#style/MyThemeOverlay" />
if you want to do it programmatically without xml, follow this link
I've noticed that using AppCompat themes, default toolbar icons get tinted by the attribute colorControlNormal in my style.
<style name="MyTheme" parent="Theme.AppCompat">
<item name="colorControlNormal">#color/yellow</item>
</style>
As you can see above, however, it does not happen with all icons. I provided the "plus" sign, which I got from the official icons, and it does not get tinted (I used the "white" version of the png). From what I have understood from this question, system tints only icons with just an alpha channel. Is this true?
If so: Is there a place where I can find alpha-defined, official material icons? If not - and if Toolbar icons need to be alpha-only to be tinted - how is Google expecting us to use provided icons in a Toolbar?
Somewhere in the SDK I found some icons ending in _alpha.png, and they actually get tinted well. However I need the full set of material icons, and from the official sources I could only find white, grey600 and black ones.
Applying a ColorFilter at runtime would be slightly painful, and my actual Toolbar - with some icons tinted, some others not - looks quite bad.
Another option is to use the new support for vector drawables in the support library.
See res/xml/ic_search.xml in blog post AppCompat — Age of the vectors
Notice the reference to ?attr/colorControlNormal
<vector xmlns:android="..."
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="?attr/colorControlNormal">
<path
android:pathData="..."
android:fillColor="#android:color/white"/>
</vector>
Here is the solution that I use. Call tintAllIcons after onPrepareOptionsMenu or the equivalent location. The reason for mutate() is if you happen to use the icons in more than one location; without the mutate, they will all take on the same tint.
public class MenuTintUtils {
public static void tintAllIcons(Menu menu, final int color) {
for (int i = 0; i < menu.size(); ++i) {
final MenuItem item = menu.getItem(i);
tintMenuItemIcon(color, item);
tintShareIconIfPresent(color, item);
}
}
private static void tintMenuItemIcon(int color, MenuItem item) {
final Drawable drawable = item.getIcon();
if (drawable != null) {
final Drawable wrapped = DrawableCompat.wrap(drawable);
drawable.mutate();
DrawableCompat.setTint(wrapped, color);
item.setIcon(drawable);
}
}
private static void tintShareIconIfPresent(int color, MenuItem item) {
if (item.getActionView() != null) {
final View actionView = item.getActionView();
final View expandActivitiesButton = actionView.findViewById(R.id.expand_activities_button);
if (expandActivitiesButton != null) {
final ImageView image = (ImageView) expandActivitiesButton.findViewById(R.id.image);
if (image != null) {
final Drawable drawable = image.getDrawable();
final Drawable wrapped = DrawableCompat.wrap(drawable);
drawable.mutate();
DrawableCompat.setTint(wrapped, color);
image.setImageDrawable(drawable);
}
}
}
}
}
This won't take care of the overflow, but for that, you can do this:
Layout:
<android.support.v7.widget.Toolbar
...
android:theme="#style/myToolbarTheme" />
Styles:
<style name="myToolbarTheme">
<item name="colorControlNormal">#FF0000</item>
</style>
This works as of appcompat v23.1.0.
I actually was able to do this on API 10 (Gingerbread) and it worked very well.
Edit: It worked on API 22 also...
Here's the final result.
Note: The icon is a drawable resource in the drawable folder(s).
Now here's how its done:
#Override
public void onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
MenuItem item = menu.findItem(R.id.action_refresh);
Drawable icon = getResources().getDrawable(R.drawable.ic_refresh_white_24dp);
icon.setColorFilter(getResources().getColor(R.color.colorAccent), PorterDuff.Mode.SRC_IN);
item.setIcon(icon);
}
At this point you can change it to any color you want!
That's the final and true answer
First create style for toolbar like this:
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" >
<item name="iconTint">#color/primaryTextColor</item>
<!--choice your favorite color-->
</style>
Then in your main app or activity theme add this line
<item name="actionBarPopupTheme">#style/AppTheme.PopupOverlay</item>
And finally in you'r layout file add this line to toolbar
android:theme="?attr/actionBarPopupTheme"
And Then you will see your toolbar icons colored in your favorite color
I see this question is getting some views so I'm going to post an answer for those who don't read the comments.
My conjectures in the question were all wrong and it is not a matter of alpha channels, at least not externally. The fact is simply that, quoting #alanv ,
AppCompat only tints its own icons. For now, you will need to manually
tint any icons that you're providing separately from AppCompat.
This might change in the future but also might not. From this answer you can also see the list of icons (they all belong to the internal resource folder of appcompat, so you can't change them) that are automatically tinted and with which color.
Personally I use a colorControlNormal which is black or white (or similar shades), and import the icons with that particular color. Colored icons on a colored background look a little bad. However, another solution I found pleasant is this class on github. You just call MenuColorizer.colorMenu() when you create the menu.
You could just create a custom Toolbar that uses your tint color when inflating the menu.
public class MyToolbar extends Toolbar {
... some constructors, extracting mAccentColor from AttrSet, etc
#Override
public void inflateMenu(#MenuRes int resId) {
super.inflateMenu(resId);
Menu menu = getMenu();
for (int i = 0; i < menu.size(); i++) {
MenuItem item = menu.getItem(i);
Drawable icon = item.getIcon();
if (icon != null) {
item.setIcon(applyTint(icon));
}
}
}
void applyTint(Drawable icon){
icon.setColorFilter(
new PorterDuffColorFilter(mAccentColor, PorterDuff.Mode.SRC_IN)
);
}
}
Just make sure you call in your Activity/Fragment code:
toolbar.inflateMenu(R.menu.some_menu);
toolbar.setOnMenuItemClickListener(someListener);
No reflection, no view lookup, and not so much code, huh?
And don't use onCreateOptionsMenu/onOptionsItemSelected, if you use this approach
For sdk 23 or higher:
<style name="AppThemeToolbar" parent="MyAppTheme">
....
<item name="android:drawableTint">#color/secondaryLightColor</item>
</style>
My toolbar
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android:theme="#style/AppThemeToolbar"
android:layout_width="match_parent"
android:layout_height="attr/actionBarSize">
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
With androidX you can define your Toolbar like this
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:theme="#style/Toolbar" />
Then, extend an AppCompat theme and set colorControlNormal property as you like:
<style name="Toolbar" parent="Theme.AppCompat.Light">
<item name="colorControlNormal">#color/colorBaseWhite</item>
<item name="android:background">#color/colorPrimary</item>
</style>
This can be done in Kotlin with:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
menu.getItem(0)?.icon?.setTint(Color.WHITE)
}
else {
#Suppress("DEPRECATION")
menu.getItem(0)?.icon?.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)
}
It should work on all modern versions of Android, and will fail without a crash if getItem or icon returns null.
try this ... 😊
menu.getItem(0).getIcon().setTint(Color.parseColor("#22CC34"));
#NonNull
public static Drawable setTintDrawable(#NonNull Drawable drawable, #ColorInt int color) {
drawable.clearColorFilter();
drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN);
drawable.invalidateSelf();
Drawable wrapDrawable = DrawableCompat.wrap(drawable).mutate();
DrawableCompat.setTint(wrapDrawable, color);
return wrapDrawable;
}
and call in this manner:
MenuItem location = menu.findItem(R.id.action_location);
DrawableUtils.setTintDrawable(location.getIcon(), Color.WHITE);
Basically, when you set menu, the three-dot icon takes up the color of android:textColorSecondary from the AppTheme, which in default is set to Black.
So if you are not using, textColorSecondary anywhere in your project, then you can simply add the following line
<item name="android:textColorSecondary">#color/White</item>
After adding it may look like this.
<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
<!-- Customise your theme here. -->
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
<item name="android:textColorSecondary">#color/White</item>
</style>