Cannot apply style for custom edit text - java

I'm trying to apply TextInputLayout theme programmatically to create a custom edit text once and use it anywhere.
This is my Custom edit text class:
package com.enjoyapps.weddingapp.view;
import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import androidx.appcompat.view.ContextThemeWrapper;
import com.enjoyapps.weddingapp.R;
import com.google.android.material.textfield.TextInputLayout;
public class CustomEditText extends TextInputLayout {
public CustomEditText(Context context) {
super(new ContextThemeWrapper(context, R.style.Widget_MaterialComponents_TextInputLayout_OutlinedBox));
init();
}
public CustomEditText(Context context, AttributeSet attrs) {
// super(context, attrs);
super(new ContextThemeWrapper(context, R.style.Widget_MaterialComponents_TextInputLayout_OutlinedBox), attrs);
init();
}
public CustomEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(new ContextThemeWrapper(context, R.style.Widget_MaterialComponents_TextInputLayout_OutlinedBox), attrs, defStyleAttr);
init();
}
private void init() {
setBoxStrokeColor(Color.BLUE);
setBoxCornerRadii(50,50,50,50);
setBoxBackgroundColor(Color.BLUE);
}
}
As you can see, in Constructor I'm setting the style with :
new ContextThemeWrapper(context, R.style.Widget_MaterialComponents_TextInputLayout_OutlinedBox)
And when i add the custom edit text to xml , it's not getting the attribute that I set in init method.
But when I apply the same theme in xml, it's working and getting the all attribute from init method.
<com.enjoyapps.weddingapp.view.CustomEditText
android:layout_width="300dp"
android:layout_centerInParent="true"
android:layout_height="50dp">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</com.enjoyapps.weddingapp.view.CustomEditText>

Which style using your app?
Just add to your main style:
<item name="editTextStyle">#style/YourStyle</item>
Example:
<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="editTextStyle">#style/YourStyle</item>
</style>

It took a bit of digging to find out the problem. Apparently, TextInputLayout uses a boxBackgroundMode in order to use certain attributes from different styles.
In addition to ContextThemeWrapper, you have to set the boxBackgroundMode for your TextInputLayout.
Therefore, if you are using :
FilledBox : you need to use BOX_BACKGROUND_FILLED
OutlinedBox : you need to use BOX_BACKGROUND_OUTLINE
In your case, just add setBoxBackgroundMode(BOX_BACKGROUND_OUTLINE) into your init():
private void init() {
// ... some styling here
setBoxBackgroundMode(BOX_BACKGROUND_OUTLINE);
}

Related

How to consider variation while switching theme?

I'm Working on an android app that has a requirement to switch theme based on the themeCode given from server. I'm using sharePref to save the theme code and applying it with setTheme(R.style.themeName);. Its working fine till the basic theme attributes like
colorPrimary
colorPrimaryDark
colorAccent
windowActionBar
windowNoTitle
For this I has created different styles in styles.xml. But I have a limitation that some fields say EditText has variation as EditText
person name
email
phone
password etc.
And similarly TextView has variation as TextView
Heading
Single Line
Mutiline
Link etc.
Before multi-theme requirement I had created separate themes for all as
Apptheme.Edittext.email
Apptheme.Edittext.Password
Apptheme.Edittext.PersonName etc.
And was applying to specific view in xml like
style="#style/AppTheme.EditText.PersonName"
Now I have viewed many tutorials/posts but did not find solution to the variations in attribute. Please help to apply these variation, I'll be thankful for this.
Regards:
Inzimam Tariq
In my opinion changing app theme at runtime, will definitely need to reload activity; this in most cases will create issues at some point (if project is extended to a mid scale, having a user control like toggle or a switch and if user taps switch repeatedly app may easily crash)
I would suggest to use custom control classes (Textviews, Buttons..etc); wherein this properties are differentiated with current theme value from sharedPref.
This approach has a con; it will require to change all views manually of current screen and those in already rendered in memory(if any), rest all it will be much smoother transition in compare to our conventional approach
EDIT: Example for CustomTextView ##
This is an example for customtextview class
public class CustomTextView extends android.support.v7.widget.AppCompatTextView {
private static final String TAG = "TextView";
private Typeface tf = null;
private SharedPreferenceUtils preferenceUtils = SharedPreferenceUtils.getInstance();
/**
* #param context:This is an abstract class whose implementation is provided by Android Operating System.
* #param attrs:A collection of attributes, as found associated with a tag in an XML document.
* #param defStyle:
*/
public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if (preferenceUtils.getBooleanValue(PrefsKeyValue.bTheme)) {
this.setTextColor(ResourceUtils.getColor(R.color.lightThemeTextColor));
} else {
this.setTextColor(ResourceUtils.getColor(R.color.colorWhite));
}
try {
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.CustomEditText, defStyle, 0);
String str = a.getString(R.styleable.CustomTextView_FontEnum);
int original = a.getInt(R.styleable.CustomEditText_FontEnum, 0);
CustomEnum.CustomFontType customEnumValue = CustomEnum.CustomFontType.fromId(a.getInt(R.styleable.CustomEditText_FontEnum, 0));
a.recycle();
switch (customEnumValue) {
case BOLD:
setTypeface(HelveticaNeueBold.getInstance(context).getTypeFace());
break;
case LIGHT:
setTypeface(HelveticaNeueMedium.getInstance(context).getTypeFace());
break;
case REGULAR:
setTypeface(HelveticaNeue.getInstance(context).getTypeFace());
break;
default:
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
public CustomTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public boolean setCustomFont(Context ctx, String asset) {
try {
tf = Typeface.createFromAsset(ctx.getAssets(), asset);
} catch (Exception e) {
LogUtils.LogE(TAG, "Could not get typeface: " + e.getMessage());
return false;
}
setTypeface(tf);
return true;
}}
Herein I have changed textcolor in accordance to theme value from sharedPref
if (preferenceUtils.getBooleanValue(PrefsKeyValue.bTheme)) {
this.setTextColor(ResourceUtils.getColor(R.color.lightThemeTextColor));
} else {
this.setTextColor(ResourceUtils.getColor(R.color.colorWhite));
}
Then use this class as textview tag in xml file.
<com.mypkg.customview.CustomTextView
style="#style/signup_textViewStyle"
android:text="#string/activity_login_password" />
I believe, you can handle property variation with theme for controls in same manner.
What you can do is create custom attributes for your view types (e.g. TextView.Person, TextView.Date...), in your xml you can reference the attributes and then define the attributes in different themes. For instance, you style.xml could be
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar" >
<item name="TextView.Date">#style/DateTextViewDefault</item>
</style>
<style name="DateTextViewDefault">
<item name="android:textColor">#ff333333</item>
<item name="android:fontFamily">monospace</item>
</style>
<!-- Theme A -->
<style name="AppTheme.A">
<item name="colorPrimary">#3F51B5</item>
<item name="colorPrimaryDark">#303F9F</item>
<item name="colorAccent">#FF4081</item>
<item name="TextView.Person">#style/PersonTextViewA</item>
</style>
<style name="PersonTextViewA">
<item name="android:textSize">16sp</item>
<item name="android:fontFamily">serif</item>
<item name="android:textColor">#ff999999</item>
</style>
<!-- Theme B -->
<style name="AppTheme.B">
<item name="colorPrimary">#888888</item>
<item name="colorPrimaryDark">#555555</item>
<item name="colorAccent">#000000</item>
<item name="TextView.Person">#style/PersonTextViewB</item>
<item name="TextView.Date">#style/DateTextViewB</item>
</style>
<style name="PersonTextViewB">
<item name="android:textSize">20sp</item>
<item name="android:fontFamily">monospace</item>
<item name="android:textColor">#ff55aa</item>
</style>
<style name="DateTextViewB">
<item name="android:textColor">#ff0000BB</item>
<item name="android:fontFamily">sans-serif</item>
</style>
<attr name="TextView.Person" format="reference" />
<attr name="TextView.Date" format="reference" />
</resources>
then your activity xml layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
style="?attr/TextView.Person"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="John Doe" />
<TextView
style="?attr/TextView.Date"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="31/12/1999" />
<Button
android:id="#+id/buttonA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="THEME A" />
<Button
android:id="#+id/buttonB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="THEME B" />
</LinearLayout>
notice that the styles of the TextView are
style="?attr/TextView.Person"
and
style="?attr/TextView.Date"
AppTheme.A and AppTheme.B have 2 different resolutions for those attributes
In this example the attributes are entire styles for your views but you could easily have one style per view type (TextView.person) and then define generic attributes for single items of that style, e.g.
<attr name="TextView.Person.TextColor" format="color" />
and only change that single attribute in your themes.
Then in your Activity you just need to set the theme in onCreate with setTheme(int), the value could be in this case either R.style.AppTheme_A or R.style.AppTheme_B.
With this method you can add as many styles as you want without touching the layouts. Also, you can always define some default styles in your base theme and then only override that value in some of the custom themes, while others use the default one as for TextView.Date in the sample above.
If you want to give it a quick try, here's the code of the Activity I used to test style.xml and activity_main.xml above
class MainActivity : AppCompatActivity() {
private val prefs by lazy { getSharedPreferences("SharedPrefs", Context.MODE_PRIVATE) }
private var customTheme: Int
get() = prefs.getInt("theme", R.style.AppTheme_A)
set(value) = prefs.edit()
.putInt("theme", value)
.apply()
.also { recreate() }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setTheme(customTheme)
setContentView(R.layout.activity_main)
buttonA.setOnClickListener { customTheme = R.style.AppTheme_A }
buttonB.setOnClickListener { customTheme = R.style.AppTheme_B }
}
}

How to a create custom view with loading animation - filling custom text from left to right?

I created loading animation with xml and played it in activity.
xml-file: anim.xml
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="#drawable/loading_00001" android:duration="50" />
<item android:drawable="#drawable/loading_00002" android:duration="50" />
<item android:drawable="#drawable/loading_00003" android:duration="50" />
<item android:drawable="#drawable/loading_00004" android:duration="50" />
<item android:drawable="#drawable/loading_00005" android:duration="50" />
</animation-list>
method in activity: playAnimation
private void playAnimation() {
ImageView imageView = (ImageView) findViewById(R.id.imageView);
imageView.setBackgroundResource(R.drawable.anim);
AnimationDrawable animation = (AnimationDrawable) imageView.getBackground();
animation.start();
}
Got:
Need create the same, but need use another way - custom view without drawable resources. Only programmatically drawing.
Something like this:
public CustomLoadingView extends View {
public CustomLoadingView(Context context) {
this(context, null);
}
public CustomLoadingView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomLoadingView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs);
}
private void init(AttributeSet attrs) {}
#Override
protected void onDraw(Canvas canvas) {}
}
What need to write inside CustomLoadingView, to get this
???
I would use transparent text with a filling rectangle underneath it. Here's how I would do it:
In some visual editing software, like paint.net, create your text on a white background, make the border orange and make the fill transparent. (You can use whatever color you want, obviously, but the transparency is necessary)
Put a rectangle with the same height, but 0 width on an activity (you can use View for this). Align it to the left and set its (background) color to orange.
In your onStart method, schedule a TimerTask to have the rectangle increase its width by say 5dp every 50ms (play around with these numbers). (You can use LayoutParams for changing the width and TimerTask for looping every x milliseconds)
When the rectangle hits the end of the screen, reset its width to 0. (You can use DisplayMetrics to determine the width of the screen in dp)
I wouldn't use a custom view.

How to set the font from Styles.xml in android

What I have:
I have a custom class inheriting AppCompatTextView.
I have defined a custom attribute textformat in attires.xml and
i am passing what font I need to set from the xml
Stylefile
<style name="HeaderFilterName">
<item name="android:src">#drawable/back_button</item>
<item name="android:text">#string/str_filter_edit</item>
<item name="android:gravity">center</item>
<item name="android:textSize">#dimen/Header_Filter_Name_Text_size</item>
<item name="android:layout_weight">1</item>
</style>
XML
<customViews.CustomTftTextView
android:id="#+id/txtScreenNameId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:textformat="fonts/sf_san_fransisco.ttf"
style="#style/HeaderFilterName"/>
attr.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="customfont">
<attr name="textformat" format="string"/>
</declare-styleable>
</resources>
CustomTftTextView.java
public class CustomTftTextView extends AppCompatTextView {
private String text;
public CustomTftTextView(final Context context) {
this(context, null);
Initialize(text,context);
}
public CustomTftTextView(final Context context, final AttributeSet attrs) {
this(context, attrs, 0);
text = context.getResources().obtainAttributes(attrs, R.styleable.customfont).getString(R.styleable.customfont_textformat);
Initialize(text,context);
}
public CustomTftTextView(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
text = context.getResources().obtainAttributes(attrs, R.styleable.customfont).getString(R.styleable.customfont_textformat);
Initialize(text,context);
}
private void Initialize(String format, Context context) {
Typeface mTypeface;
if (format != null)
{
mTypeface = Typeface.createFromAsset(context.getAssets(), format);
}
else
{
mTypeface = Typeface.createFromAsset(context.getAssets(), "fonts/sf_san_fransisco.ttf");
}
setTypeface(mTypeface, Typeface.NORMAL);
setLineSpacing(0.0f, 1.4f);
}
}
While above code works perfect, If I move app:textformat inside the style file, The font is not setting.
<style name="HeaderFilterName">
<item name="android:src">#drawable/back_button</item>
<item name="android:text">#string/str_filter_edit</item>
<item name="textformat">#string/custom_font_medium </item>
<item name="android:gravity">center</item>
<item name="android:textSize">#dimen/Header_Filter_Name_Text_size</item>
<item name="android:layout_weight">1</item>
</style>
strings.xml
<string name="custom_font_medium">fonts/sf_san_fransisco.ttf</string>
How properly achieve this
If you check the docs for the Resources#obtainAttributes() method, it says:
Retrieve a set of basic attribute values from an AttributeSet, not performing styling of them using a theme and/or style resources.
To get the attributes with your style applied, use a Context#obtainStyledAttributes() method instead. It would also be advisable to keep a reference to that return, so you can recycle() it when done. For example:
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.customfont);
text = a.getString(R.styleable.customfont_textformat);
a.recycle();
Make sure in styles.xml you used namespace like below
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app='http://schemas.android.com/apk/res-auto'>

Android: Updating custom color attribute using selector

I would like to define what color should be used when painting to a canvas depending on a custom state. This is how far I got:
In res/layout/content.xml:
<com.example.package.MyView
app:primary_color="#drawable/my_selector"
/>
primary_color is a custom attribute defined in res/values/attrs.xml:
<resource>
<declare-styleable name="MyView">
<attr name="primary_color" format="reference"/>
</declare-styleable>
</resource>
my_selector is defined in res/drawable/my_selector.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.example.package">
<item
app:state_a="true"
android:drawable="#drawable/red" />
<item
app:state_b="true"
android:drawable="#drawable/orange" />
<item
app:state_c="true"
android:drawable="#drawable/red" />
</selector>
red, orange and red are defined in res/values/colordrawable.xml:
<resources>
<drawable name="red">#f00</drawable>
<drawable name="orange">#fb0</drawable>
<drawable name="green">#0f0</drawable>
</resources>
In MyView I can get this drawable:
StateListDrawable primaryColor;
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
try{
primaryColor = (StateListDrawable) a.getDrawable(
R.styleable.MyView_primary_color);
}finally {
a.recycle();
}
}
primaryColor updates correctly with the different states, I can test this by calling:
setBackground(primaryColor);
But I want to use this color with Paint, like this:
paint.setColor(primaryColor);
But this is obviously not allowed. I've tried converting the primaryColor to a ColorDrawable which has the method getColor(), but I can't figure out how to do this, if it is possible.
Any suggestions on how to get the color that can be used in the the view from a selector would be amazing.
I found ColorStateList which turned out to be exactly what I needed. The following is a simplified version of my current implementation, in case someone else gets in the same rut as I did.
In res/color/my_selector.xml
<?xml version="1.0" encoding="utf-8" ?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"">
<item app:state_weak="true" android:color="#F00" />
<item app:state_average="true" android:color="#0F0" />
<item app:state_strong="true" android:color="#00F" />
<item android:color="#FA0" />
</selector>
In res/layout/content.xml (This has another layout wrapped around it, but that is not relevant)
<com.example.package.MyView
android:id="#+id/strMeter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:primary_color="#color/my_selector"
/>
primary_color is defines as a reference in res/values/attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyView">
<attr name="primary_color" format="reference"/>
</declare-styleable>
</resources>
I get the reference to the ColorStateList in the constructor of MyView:
ColorStateList primaryColor;
public PasswordStrengthBar(Context context, AttributeSet attrs) {
super(context, attrs);
try{
primaryColor = a.getColorStateList(
R.styleable.MyView_primary_color);
}finally {
a.recycle();
}
}
When I want to get the color for the current state:
int color = secondaryColor.getColorForState(
getDrawableState(), primaryColor.getDefaultColor());
If you implement a custom state, like I did, then you will also have to override onCreateDrawableState for the states to actually update, but there is plenty of documentation/posts that cover that.

Changing EditText bottom line color with appcompat v7

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

Categories