Cambio del color de la línea de fondo de EditText con appcompat v7


310

Estoy usando appcompat v7 para obtener un aspecto consistente en Android 5 y menos. Funciona bastante bien. Sin embargo, no puedo entender cómo cambiar el color de la línea de fondo y el color de acento para EditTexts. ¿Es posible?

Intenté definir una costumbre android:editTextStyle(ver abajo) pero solo logré cambiar el color de fondo completo o el color del texto, pero no la línea de fondo ni el color de acento. ¿Hay un valor de propiedad específico para usar? ¿Tengo que usar una imagen dibujable personalizada a través de la android:backgroundpropiedad? ¿No es posible especificar un color en 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>

Según las fuentes de Android API 21, EditTexts con diseño de material parece usar colorControlActivatedy colorControlNormal. Por lo tanto, he intentado anular estas propiedades en la definición de estilo anterior, pero no tiene ningún efecto. Probablemente appcompat no lo use. Desafortunadamente, no puedo encontrar las fuentes para la última versión de appcompat con diseño de material.


define tu tema para editar texto
Meenal

Gracias por su sugerencia pero ya lo hice. He actualizado mi pregunta para mostrar lo que ya he intentado hacer. Mi problema es sobre el atributo a usar en el estilo del tema para cambiar el color de la línea de fondo del texto de edición. Idealmente, estoy buscando una solución donde pueda especificar directamente el color en hexa.
Laurent

Ninguna de estas respuestas me funciona en 4.3. ¿Tienes una solución que funcione?
Robert Baker

Tuve que extender AppCompatEditText, aparentemente.
EpicPandaForce

Respuestas:


479

Finalmente, he encontrado una solución. Consiste simplemente en sustituir el valor de colorControlActivated, colorControlHighlighty colorControlNormalen la definición del tema de aplicación y no su estilo EditarTexto. Luego, piense en usar este tema para cualquier actividad que desee. A continuación se muestra un ejemplo:

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

99
Veo que el color de la hamburguesa del menú, el botón de retroceso y la barra de desplazamiento han cambiado a colorControlNormal.
ario

11
Esto cambia el color de la línea de fondo, pero también cambia cualquier otro control, como casillas de verificación, botones de opción, etc. También cambia cada EditText en toda la Aplicación / Actividad. Si desea cambiar la línea inferior de un único EditText (como lo hago yo), entonces tiene que anular la propiedad android: background para ese EditText. No hay otra forma de AFAIK.
Emanuel Moecklin

68
Si está utilizando la biblioteca de soporte v22 AppCompat, puede especificar el tema en el EditarTexto como: android:theme="@style/Theme.App.Base. Esto asegurará que el estilo no afectará otras vistas en sus diseños que no desea cambiar.
Alex Lockwood

8
No funcionó en Jelly Bean (4.2) pero funcionó en Lollipop
Mangesh

3
La actividad debe heredar de AppCompatActivity. No funcionará si hereda de Activity.
Bharathwaaj

187

Sentí que esto necesitaba una respuesta en caso de que alguien quisiera cambiar un solo texto de edición. Lo hago así:

editText.getBackground().mutate().setColorFilter(ContextCompat.getColor(context, R.color.your_color), PorterDuff.Mode.SRC_ATOP);

1
Pero, ¿cómo puedo restablecer el fondo predeterminado, tengo muchos errores después de llamar a editText.getBackground (). ResetColorFilter () en Lollipop?
ultraon

¡Precaución! agregar esto puede hacer que cambie el color de editText en TODAS las aplicaciones. Probado en Nexus 5. OS 6.0.1.
Alex Perevozchykov

1
@AlexPerevozchykov puede que tengas razón. Intente agregar .mutate () después de .getBackground (). Deberias hacer eso.
hordurh

@hordurh sí, lo fue, recibí esta sugerencia un poco antes, los sorteos comparten un grupo, así que antes de cambiar tenemos que mutarlo
Alex Perevozchykov

1
Si uso edittext, funciona pero este método no funciona con la aplicación compat edittext en lollipop. ¿Sabes cómo puedo resolver el problema?
Selin

145

Mientras que la solución Laurents es correcta, viene con algunos inconvenientes que se han descrito en los comentarios ya que no sólo la línea inferior de la EditTextconsigue teñido pero el botón de retorno de la Toolbar, CheckBoxesetc., así.

Por suerte v22.1de appcompat-v7introdujo algunas nuevas posibilidades. Ahora es posible asignar un tema específico solo a una vista. Directamente desde el registro de cambios :

Uso obsoleto de la aplicación: tema para el diseño de la barra de herramientas. Ahora puede usar android: theme para barras de herramientas en todos los dispositivos API nivel 7 y superior y android: tema de soporte para todos los widgets en dispositivos API nivel 11 y superior.

Entonces, en lugar de establecer el color deseado en un tema global, creamos uno nuevo y lo asignamos solo a EditText.

Ejemplo:

<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"/>

1
No creo que esto sea necesario. colorControlNormalsin el prefijo de Android utiliza el método appcompat para teñir widgets, mientras que con el prefijo recurre al método del sistema y esto solo está disponible en dispositivos API 21+.
reVerse

hmm, probé en mi dispositivo lollipop y no se matizará con el color personalizado a menos que lo implemente en estilos v21 con el espacio de nombres de Android también.
user2968401

Estoy usando la 22.2.0versión de AppCompat pero este truco no funciona :(
Shajeel Afzal

1
El uso de <item name = "colorAccent"> # 000000 </item> funcionó para mí en lugar de colorControlNormal.
MikeOscarEcho

¡Perfecto para cambiar solo un texto de edición en la aplicación! (¡Exactamente lo que necesitaba! Gracias)
Romain Barbier

99

Esto se puede cambiar en XML usando:

Para la API de referencia> = 21, use la compatibilidad:

android:backgroundTint="@color/blue"

Para el uso de compatibilidad con API <21 anterior:

app:backgroundTint="@color/blue"

10
Sí, sin embargo, esto solo funciona para las versiones de API de Android 21+ (kitkat y lolipop). Uno probablemente trataría de crear una solución compatible con versiones anteriores.
DaMachk

12
Solo use en backgroundTint="@color/blue"lugar de android:backgroundTint="@color/blue"soporte compatible con versiones anteriores
Kishan Vaghela

11
@KishanVaghela, en lugar de usar android:backgroundTint="@color/blue", usar app:backgroundTint="@color/blue"para admitir dispositivos pre-Lollipop, ¡gracias por tu comentario!
blueware

2
@blueware Si quiere usarlo con estilo, entonces no necesitamos usar "app".
Kishan Vaghela

agregar tools:ignore="MissingPrefix"si app:backgroundTint="<your color>"
aparece

47

Aquí está la solución para API <21 y superior

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
}

ingrese la descripción de la imagen aquí

Espero que ayude


@CoolMind lo siento por la respuesta tardía. Tengo comprobar el código de nuevo en la biblioteca de soporte 24.2.1, 25.1.1, 25.2.0para el dispositivo <21 y> 21 y se sigue trabajando. Consulte esta demostración simple drive.google.com/file/d/0B_poNaia6t8kSzU3bDFVazRSSDA/… . No sé por qué este código no funciona para usted, así que hágamelo saber. gracias
Phan Van Linh

@ Renjith perdón por la respuesta tardía, por favor revise mi comentario anterior
Phan Van Linh

¿Cómo restablece el color predeterminado con este código?
Neph

35

La respuesta aceptada es un poco más por estilo, pero lo más eficiente es agregar el atributo colorAccent en su estilo AppTheme de esta manera:

<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"/>

El atributo colorAccent se usa para el tinte de widgets en toda la aplicación y, por lo tanto, debe usarse para mantener la coherencia.


8
@Tomasz no requiere API 21+ porque el tema principal es AppCompat que se reduce a API 7
TanmayP

Ughhh Gracias por esto, estaba usando por name="android:colorAccent"error
Jules

29

Si está usando appcompat-v7:22.1.0+, puede usar DrawableCompat para teñir sus 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);
    }

qué salvavidas esto es increíble, una pena que no se conozca bien
pt123

Mueva hacia abajo y vea mi respuesta para la biblioteca de diseño 23.2.0. Este método es inútil en este momento.
ywwynm

21

Utilizar:

<EditText
    app:backgroundTint="@color/blue"/>

Esto admitirá dispositivos pre-Lollipop no solo +21


@ powder366, ¿puedes publicar el tema principal de tu aplicación?
blueware

1
<style name = "AppTheme" parent = "Theme.AppCompat.Light.DarkActionBar">
powder366

2
@ powder366, prueba esto: <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">y debería funcionar
blueware

19

<!-- 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>


¡Funciona! Como la pregunta pregunta, debe resolverse en el estilo / tema, esta debe ser la respuesta correcta.
Ninja

Estoy de acuerdo. esta debería ser la respuesta correcta, ya que es una solución global
Santacrab

Esto es inconveniente si diferentes controles necesitan diferentes colores.
Julius

12

Una solución rápida para su problema es buscar en su paquete / build / intermedios / exploded-aar / com.android.support / appcompat-v7 / res / drawable / for abc_edit_text_material.xml y copiar ese archivo xml en su carpeta dibujable. Luego puede cambiar el color de los 9 archivos de parche desde este selector, para que coincida con sus preferencias.


9

Es muy fácil simplemente agregar android:backgroundTintatributo en su 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"/>

2
backgroundTint por encima del nivel API 21
Ashwin H

ViewCompat.setBackgroundTintList (editText, ColorStateList.valueOf (Color.YELLOW))
Primero el

1
app:backgroundTint="@color/blue" funciona en todos los niveles de la API ... aunque, por cualquier motivo, sigue cambiando a un color diferente cuando se selecciona XD
EpicPandaForce

8

Aquí hay una parte del código fuente de la TextInputLayoutbiblioteca de diseño de soporte ( ACTUALIZADO para la versión 23.2.0 ), que cambia EditTextel color de la línea de fondo de una manera más simple:

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

Parece que todo el código anterior se vuelve inútil en este momento en 23.2.0 si desea cambiar el color mediante programación.

Y si quieres soportar todas las plataformas, aquí está mi método:

/**
 * 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);
}

¿Qué es AppCompatDrawableManager? setBackground requiere API 16.
CoolMind

8

Yo también estuve atrapado en este problema durante demasiado tiempo.

Necesitaba una solución que funcionara para las versiones anteriores y posteriores a v21.

Finalmente descubrí una solución muy simple, quizás no ideal pero efectiva: simplemente configure el color de fondo transparenten las propiedades EditText.

<EditText
    android:background="@android:color/transparent"/>

Espero que esto ahorre algo de tiempo.


1
Esto está cambiando todo el color de fondo, y queremos cambiar solo el color de subrayado.
Shahzain Ali

@shahzain ali El subrayado de EditText es un fondo. Se ha ido si lo configuras como nulo. Y es por eso que backgroundTint funcionará (pero no cambiará de color cuando se active)
nyconing

7

Para mí, modifiqué el AppTheme y un valor colors.xml Tanto el colorControlNormal como el colorAccent me ayudaron a cambiar el color del borde EditText. Así como el cursor y el "|" cuando dentro de un 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>

Aquí está el colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="yellow">#B7EC2A</color>
</resources>

Saqué el atributo android: textCursorDrawable a @null que coloqué dentro del estilo editText. Cuando intenté usar esto, los colores no cambiaron.


2
Esta debería ser la respuesta
Mina Samy

Trabajado como un encanto. Gracias
Däñish Shärmà

6

Puede configurar el fondo del texto de edición en un rectángulo con relleno menos a la izquierda, derecha y arriba para lograr esto. Aquí está el ejemplo xml:

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

Reemplace la forma con un selector si desea proporcionar un ancho y un color diferentes para el texto de edición enfocado.


5

En Activit.XML agregue el código

<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"/>

Donde BackgroundTint=colorpara su color deseado


5

Utilizo este método para cambiar el color de la línea con PorterDuff, sin otro dibujable.

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

¿Existe un identificador similar para acceder a la línea inferior de un simple EditText?
Rémi P

4

Si desea cambiar el resultado final sin usar los colores de la aplicación, use estas líneas en su tema:

<item name="android:editTextStyle">@android:style/Widget.EditText</item>
<item name="editTextStyle">@android:style/Widget.EditText</item>

No conozco otra solución.


4

Desarrollé una solución funcional para este problema después de 2 días de lucha, la solución a continuación es perfecta para aquellos que desean cambiar solo algunos textos de edición, cambiar / alternar el color a través del código de Java y quieren superar los problemas de comportamiento diferente en las versiones del sistema operativo debido al uso del método setColorFilter ().

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

Usos en 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"/>

Agregar líneas con estilo

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

código java para alternar color

myRqubeEditText.setErrorState(true);
myRqubeEditText.setErrorState(false);

2

Estaba absolutamente desconcertado por este problema. Había intentado todo en este hilo y en otros, pero no importa lo que hice, no pude cambiar el color del subrayado a otro que no sea el azul predeterminado.

Finalmente descubrí lo que estaba pasando. Estaba usando (incorrectamente) android.widget.EditTextal hacer una nueva instancia (pero el resto de mis componentes eran de la biblioteca appcompat). Debería haberlo usado android.support.v7.widget.AppCompatEditText. He sustituido new EditText(this)con new AppCompatEditText(this) y el problema se solucionó al instante. Resulta que, si realmente está usando AppCompatEditText, solo respetará el accentColortema (como se menciona en varios comentarios anteriores) y no es necesaria una configuración adicional.


2

Este es el más fácil y más eficiente / reutilizable / funciona en todas las API
Cree una clase personalizada de EditText de esta manera:

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

Entonces úsalo así:

 <company.com.app.EditText
        android:layout_width="200dp"
        android:layout_height="wrap_content"/>

2

Para cambiar el fondo EditText dinámicamente, puede usar 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);

Créditos: Esta respuesta SO sobre ColorStateList es increíble .


¿Y qué método usar? setBackgroundTintList? Requiere API 21.
CoolMind


0

Agregue app:backgroundTintpor debajo del nivel de API 21. De lo contrario, useandroid:backgroundTint .

Por debajo del nivel 21 de la API.

<EditText
     android:id="@+id/edt_name"
     android:layout_width="300dp"
     android:layout_height="wrap_content"
     android:textColor="#0012ff"
     app:backgroundTint="#0012ff"/>

Para niveles superiores al nivel 21 de la API.

<EditText
     android:id="@+id/edt_name"
     android:layout_width="300dp"
     android:layout_height="wrap_content"
     android:textColor="#0012ff"
     android:backgroundTint="#0012ff"/>

-2

Modifique este método según sus necesidades. ¡Esto funcionó para mí!

  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());
        }
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.