Apply Style to MaterialButton programmatically - android

I'm trying to create a custom view extending from MaterialButton and apply style in code so I don't need to do it in xml.
class CustomRedButton #JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : MaterialButton(ContextThemeWrapper(context, R.style.ButtonRedStyle), attrs, defStyleAttr)
Style is:
<style name="ButtonRedStyle"
parent="Widget.MaterialComponents.Button.TextButton">
<item name="backgroundTint">#color/red</item>
<item name="rippleColor">#color/grey</item>
<item name="strokeWidth">1dp</item>
<item name="strokeColor">#color/black</item>
</style>
Everything works fine but backgroundTint property. For some reason background color is not changing, and it has Theme's primary color. However, if I try to apply the style to a MaterialButton in xml it does change the color.
Any idea why that can be happening or how I can achieve it?

Using
MaterialButton(ContextThemeWrapper(context, R.style.ButtonRedStyle), attrs, defStyleAttr)
you are applying a themeoverlay to default style, you are not applying a different style.
It means:
<style name="ButtonRedTheme" parent="...">
<item name="colorPrimary">#color/...</item>
<item name="colorOnPrimary">#color/...</item>
<item name="colorSecondary">#color/...</item>
</style>
If you want to apply a different style you have to:
Define a custom attribute in attrs.xml
<attr name="myButtonStyle" format="reference"/>
Assing a style to this attribute in your app theme:
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight">
<item name="myButtonStyle">#style/CustomButtonStyle</item>
</style>
Define the custom style:
<style name="CustomButtonStyle" parent="Widget.MaterialComponents.Button.*">
<item name="backgroundTint">#color/...</item>
<item name="rippleColor">#color/grey</item>
<item name="strokeWidth">1dp</item>
<item name="strokeColor">#color/black</item>
</style>
Finally use:
val customButton = MaterialButton(context, null, R.attr.myButtonStyle)

I'm also facing the same issue. The only workaround I've found so far is to set the tint programmatically like:
button.setBackgroundTintList(ColorStateList.valueOf(Color.RED));

For a TextButton there shouldn't be a background (just the text has a color). For a colored button, you should use the default Filled Button style which is Widget.MaterialComponents.Button.
And when applied as a theme, the button uses different attributes. It's described in section Themed Attribute Mapping here: https://material.io/develop/android/components/material-button/
Filled button
+------------------------+-----------------------------------------+
| Component Attribute | Default Theme Attribute Value |
+------------------------+-----------------------------------------+
| android:textAppearance | textAppearanceButton |
| android:textColor | colorOnPrimary |
| iconTint | colorOnPrimary |
| rippleColor | colorOnPrimary at 32% opacity (pressed) |
| iconTint | colorOnPrimary |
| backgroundTint | colorPrimary |
| ... | ... |
+------------------------+-----------------------------------------+
In your case, the theme should look something like:
<style name="ButtonRedTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
<item name="colorPrimary">#color/red</item>
<item name="colorOnPrimary">#color/white</item>
<item name="colorOnSurface">#color/black</item>
</style>
You can also change all buttons to a specific style with
<item name="materialButtonStyle">#style/ButtonRedTheme</item>
in your app theme.

If you want to change your style for CustomView, you've to pass it to constructor by passing it into third param defStyleAttr like this:
class CustomRedButton #JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = R.style.ButtonRedStyle // Just default style like this
) : MaterialButton(context, attrs, defStyleAttr)
and you can initialize it like this programmatically,
CustomRedButton(this, null, R.style.ButtonRedStyle) // Initialization, ('this' is context)
For more details refer here

I had the same issue for a simple use case, i need to update the button backgroundTint and isEnabled state
what i did:
i created a custom class that extends from MaterialButton
class MyCustomMaterialButton #JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
) : MaterialButton(context, attrs)
then i added an extension to this class to update button styling attributes:
fun MyCustomMaterialButton.updateEnabledState(enabled: Boolean){
apply {
if(enabled){
isEnabled = true
setBackgroundColor(ContextCompat.getColor(context, R.color.primary))
}
else{
isEnabled = false
setBackgroundColor(ContextCompat.getColor(context, R.color.primary_warm_grey_five))
}
}
}
this is how it looks like in Xml:
<com.karny.branding.KarnyMaterialButton
android:id="#+id/smsAuthButton"
style="#style/PrimaryButtonDisabled"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="94dp"
android:layout_marginBottom="24dp"
android:text="#string/sms_auth_check"
app:layout_constraintEnd_toStartOf="#+id/left_middle_guide_line"
app:layout_constraintStart_toEndOf="#+id/right_middle_guide_line"
app:layout_constraintTop_toBottomOf="#+id/smsAuthNumberContainer" />

Related

Define style and custom attribute in View instead of xml

I want to implement custom style for view. Let's take an example of button. Some common values will be shared across the app for that I am using style like below:
<style name="Widget.Demo.Button.Primary" parent="#style/Widget.MaterialComponents.Button">
<item name="fontFamily">#font/roboto</item>
<item name="android:fontFamily">#font/roboto</item>
<item name="android:minHeight">64dp</item>
<item name="android:theme">#style/ThemeOverlay.Demo.GrayPrimary</item>
</style>
<style name="ThemeOverlay.Demo.GrayPrimary" parent="">
<item name="colorPrimary">#color/gray</item>
</style>
Now I want to add some of the custom attribute in the button like below (This is just an example not the real attribute):
<com.android.CustomButton
android:id="#+id/btn_first"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/first"
app:abc="primary"
style="#style/Widget.Demo.Button.Primary"/>
attrs.xml:
<declare-styleable name="CustomButtonAttr" >
<attr name="abc" format="enum" >
<enum name="primary" value="1"/>
<enum name="secondary" value="2"/>
</declare-styleable>
I don't want to define style and custom attribute in xml everytime. Is there any way to get custom attribute directly in my customview and Widget.Demo.Button.Primary set by default in my below class?
class CustomButton : MaterialButton {
constructor(context: Context) : super(context)
constructor(context: Context, attributeSet: AttributeSet) : super(
ThemeEnforcement.createThemedContext(context, attributeSet, 0, 0),
attributeSet,
0
)
}
I don't want to define style in xml for every button or view which I create. So is there a way to define in CustomButton class along with custom attributes ? If yes could you please give me some references.
Thanks in advance.
Yep, you can use the default style attribute in the constructor.
Define a new attribute:
<attr name="customButtonStyle" format="reference" />
Then use the appropriate view constructor:
private val defStyleAttr = R.attr.customButtonStyle
class CustomButton(context: Context, attrs: AttributeSet) : MaterialButton(
ThemeEnforcement.createThemedContext(context, attributeSet, defStyleAttr, 0),
attributeSet,
defStyleAttr
) {
init {
val typedArray = context.obtainStyledAttributes(
attrs,
R.styleable.CustomButton,
defStyleAttr,
0
)
...
}
In your theme, point customButtonStyle to the style resource that you want used by default:
<style name="Theme.Demo" parent="Base.Theme.Demo">
<item name="customButtonStyle">#style/Widget.Demo.Button.Primary</item>
</style>
Note that android:theme should be changed to materialThemeOverlay in that style resource, as it won't be applied when read from a default style. As you're already wrapping the context with the ThemeEnforcement function (newer versions of Material Design Components change this to MaterialThemeOverlay), this custom view supports materialThemeOverlay 👍
You can add your custom attributes to the style too:
<style name="Widget.Demo.Button.Primary" parent="#style/Widget.MaterialComponents.Button">
<item name="abc">primary</item>
<item name="fontFamily">#font/roboto</item>
<item name="android:fontFamily">#font/roboto</item>
<item name="android:minHeight">64dp</item>
<item name="materialThemeOverlay">#style/ThemeOverlay.Demo.GrayPrimary</item>
</style>
Reference (blog + video)

Extending MaterialCardView doesn't apply themes

According to the material specifications https://material.io/develop/android/components/material-card-view/ colorSurface applies to the card's Background color .
This works when we are specifying the card in our xml like this
<com.google.android.material.card.MaterialCardView
android:layout_width="100dp"
android:layout_height="100dp"></com.google.android.material.card.MaterialCardView>
When I run this I can see color surface properly being applied to the above card.
This also works if I make a card programmatically
addView(MaterialCardView(this).apply {
layoutParams = ViewGroup.LayoutParams(300,300)
})
However once I extend from MaterialCardView to make my own custom view , it appears as if the theme connection to this is lost . The color surface is not applied rather the card defaults to white
class CustomView #JvmOverloads constructor(
context: Context?,
attributeSet: AttributeSet? = null,
defStyleAttr: Int = 0
) : MaterialCardView(context, attributeSet, defStyleAttr){
}
<com.seed.formviewactivity.CustomView
android:layout_width="100dp"
android:layout_height="100dp"></com.seed.formviewactivity.CustomView>
My CustomView now doesn't have the colorSurface applied.
Is this a known issue ?
In your constructor you are using defStyleAttr: Int = 0.
You should apply the R.attr.materialCardViewStyle as default value instead of 0.
In this way your custom CardView will use the style defined in you app theme by materialCardViewStyle attribute.
The default value provided by the Material Components Library is:
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight">
<!-- ... -->
<item name="materialCardViewStyle">#style/Widget.MaterialComponents.CardView</item>
</style>

Button not showing Material Design

I've found out that the reason is that I'm using the Android-Iconics library - I removed the context injection and everything is fine now.
I'm using a combination of XML Layouts and Anko DSL to build my app and I've noticed that the button design is different depending on how it's generated.
In case it's an Anko-generated button, the text is in caps (what I think it should be in Material) and has a ripple effect. If the button is created by XML the text is lowercase and without the effect.
The upper button is the XML one, so here you can see the difference.
I've tried setting a custom style to the button but it doesn't seem to work - I can't even make textAllCaps=true work.
Currently I'm using androidx and extending AppCompat & Theme.AppCompat.Light.NoActionBar and I've tried extending Widget.AppCompat.Button to set a custom style to the view without luck.
This is happening in all API levels (24, 26 and 28). In the XML preview it does show fine.
The current XML is
<Button
android:text="#string/compartir"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/debunkShareButton"
android:textAllCaps="true"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintTop_toBottomOf="#+id/debunkTitle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
style="#style/Full_Yellow_Button"/>
And the Full_Yellow_Button is
<style name="Full_Yellow_Button" parent="Widget.AppCompat.Button">
<item name="android:background">#drawable/yellow_gradient</item>
</style>
Any ideas? Thanks!
If you are using new material design components make sure your application theme extends from main theme Theme.MaterialComponents or other relavant theme.
<style name="Theme.MyApp" parent="Theme.MaterialComponents.Light">
<!-- ... -->
</style>
Also, instead of using generic Button class to define button, You need to use com.google.android.material.button.MaterialButton in your xml and java both.
<com.google.android.material.button.MaterialButton
android:id="#+id/material_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/button_label_enabled"/>
Your theme should be extended from Theme.MaterialComponents.xxxxx
like this XML block
<style name="AppTheme" parent="Theme.MaterialComponents.Light.DarkActionBar">
You can create your TextView class for set to uppercase
class UppercaseTextView : TextView, ViewTreeObserver.OnPreDrawListener {
constructor(context: Context) : super(context) {}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {}
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {}
override fun setText(text: CharSequence, type: BufferType) {
super.setText(text.toString().toUpperCase(), type)
}
}

Changing EditText bottom line color android [duplicate]

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

How to: Define theme (style) item for custom widget

I've written a custom widget for a control that we use widely throughout our application. The widget class derives from ImageButton and extends it in a couple of simple ways. I've defined a style which I can apply to the widget as it's used, but I'd prefer to set this up through a theme. In R.styleable I see widget style attributes like imageButtonStyle and textViewStyle. Is there any way to create something like that for the custom widget I wrote?
Yes, there's one way:
Suppose you have a declaration of attributes for your widget (in attrs.xml):
<declare-styleable name="CustomImageButton">
<attr name="customAttr" format="string"/>
</declare-styleable>
Declare an attribute you will use for a style reference (in attrs.xml):
<declare-styleable name="CustomTheme">
<attr name="customImageButtonStyle" format="reference"/>
</declare-styleable>
Declare a set of default attribute values for the widget (in styles.xml):
<style name="Widget.ImageButton.Custom" parent="android:style/Widget.ImageButton">
<item name="customAttr">some value</item>
</style>
Declare a custom theme (in themes.xml):
<style name="Theme.Custom" parent="#android:style/Theme">
<item name="customImageButtonStyle">#style/Widget.ImageButton.Custom</item>
</style>
Use this attribute as the third argument in your widget's constructor (in CustomImageButton.java):
public class CustomImageButton extends ImageButton {
private String customAttr;
public CustomImageButton( Context context ) {
this( context, null );
}
public CustomImageButton( Context context, AttributeSet attrs ) {
this( context, attrs, R.attr.customImageButtonStyle );
}
public CustomImageButton( Context context, AttributeSet attrs,
int defStyle ) {
super( context, attrs, defStyle );
final TypedArray array = context.obtainStyledAttributes( attrs,
R.styleable.CustomImageButton, defStyle,
R.style.Widget_ImageButton_Custom ); // see below
this.customAttr =
array.getString( R.styleable.CustomImageButton_customAttr, "" );
array.recycle();
}
}
Now you have to apply Theme.Custom to all activities that use CustomImageButton (in AndroidManifest.xml):
<activity android:name=".MyActivity" android:theme="#style/Theme.Custom"/>
That's all. Now CustomImageButton tries to load default attribute values from customImageButtonStyle attribute of current theme. If no such attribute is found in the theme or attribute's value is #null then the final argument to obtainStyledAttributes will be used: Widget.ImageButton.Custom in this case.
You can change names of all instances and all files (except AndroidManifest.xml) but it would be better to use Android naming convention.
Another aspect in addition to michael's excellent answer is overriding custom attributes in themes.
Suppose you have a number of custom views that all refer to the custom attribute "custom_background".
<declare-styleable name="MyCustomStylables">
<attr name="custom_background" format="color"/>
</declare-styleable>
In a theme you define what the value is
<style name="MyColorfulTheme" parent="AppTheme">
<item name="custom_background">#ff0000</item>
</style>
or
<style name="MyBoringTheme" parent="AppTheme">
<item name="custom_background">#ffffff</item>
</style>
You can refer to the attribute in a style
<style name="MyDefaultLabelStyle" parent="AppTheme">
<item name="android:background">?background_label</item>
</style>
Notice the question mark, as also used for reference android attribute as in
?android:attr/colorBackground
As most of you have noticed, you can -and probably should- use #color references instead of hard coded colors.
So why not just do
<item name="android:background">#color/my_background_color</item>
You can not change the definition of "my_background_color" at runtime, whereas you can easily switch themes.

Categories

Resources