El backgroundTint de Lollipop no tiene ningún efecto en un botón


82

Tengo un botón en mi actividad y me gustaría que tuviera el color de acento de mi tema. En lugar de hacer mis propios dibujables como teníamos que hacer antes de Lollipop, naturalmente me gustaría usar el nuevo backgroundTintatributo.

<Button
    android:id="@+id/btnAddCode"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:backgroundTint="@color/accent"
    android:text="@string/addressInfo_edit_addCode" />

Desafortunadamente, no tiene ningún efecto, el botón permanece gris.

Probé diferentes valores para backgroundTintMode, que no cambiaron nada.

También intenté hacerlo programáticamente en mi Actividad, lo que no cambió nada.

addCodeView.findViewById(R.id.btnAddCode).setBackgroundTintList(
     getResources().getColorStateList(R.color.accent));

¿Por qué se ignora mi tinte?

EDITAR: Solo para aclarar, de hecho estoy probando en un dispositivo Lollipop. Otros widgets (por ejemplo, EditText) se tiñen de forma correcta y automática.


3
Este es un error que se ha corregido para una versión futura, pero la solución aceptada funcionará en API 21+.
Alanv

Respuestas:


18

Probado en API 19 a API 27

<?xml version="1.0" encoding="utf-8"?>
  <android.support.v7.widget.AppCompatButton 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    style="@style/Widget.AppCompat.Button.Colored"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/retry"
    android:textColor="@android:color/white"
    app:backgroundTint="@android:color/holo_red_dark" />

produce salida como -

ingrese la descripción de la imagen aquí


Marcando esto como la respuesta aceptada porque después de varios años, creo que ahora es la forma oficial (y mejor) de hacer esto. (Detalle menor: estoy bastante seguro de que en la mayoría de los casos simplemente puede usar Button en lugar de AppCompatButton y seguirá funcionando).
BoD

117

Las malas noticias

Como dice BoD, no tiene sentido teñir los antecedentes de un Button en Lollipop 5.0 (API nivel 21).

Las buenas noticias

Lollipop 5.1 (API nivel 22) parece haber solucionado este problema cambiando btn_mtrl_default_shape.xml (entre otros archivos): https://android.googlesource.com/platform/frameworks/base/+/6dfa60f33ca6018959ebff1efde82db7d2aed1e3%5E!/#

La gran noticia

La nueva biblioteca de soporte (versión 22.1+) agrega soporte de tintado compatible con versiones anteriores a muchos componentes, incluido AppCompatButton .

Desafortunadamente, la android:backgroundTintpropiedad aún no funciona (tal vez estoy haciendo algo mal), por lo que debe configurar el ColorStateListcódigo in, usando setSupportBackgroundTintList(). Sería muy bueno ver el android:backgroundTintapoyo en el futuro. Actualización : ¡Marcio Granzotto comentó que app:backgroundTintfunciona en AppCompatButton! Tenga en cuenta que no lo es app:, android:porque está en la aplicación / biblioteca.

<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <AppCompatButton
        android:id="@+id/mybutton"
        android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:text="Testing, testing"
        app:backgroundTint="#ff00ff"/>

</LinearLayout>

Su actividad se inflará automáticamente en AppCompatButtonlugar de lo normal Buttonsi deja que herede AppCompatActivity.

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        AppCompatButton v = (AppCompatButton) findViewById(R.id.mybutton);
        ColorStateList csl = new ColorStateList(new int[][]{new int[0]}, new int[]{0xffffcc00});
        v.setSupportBackgroundTintList(csl);
    }
}

Por supuesto, debería obtener el ColorStateListde un recurso de color, pero yo era un vago, así que ...

Ah, y no olvides basar el tema de tu aplicación en uno de los Theme.AppCompattemas, o las vistas compatibles serán muy, muy tristes ...;)

Esto funcionó tanto en 2.3.7 (Gingerbread MR1) como en 5.0 (Lollipop 'Classic').


1
Acabo de agregar más información; lo más importante, ahora es posible lograr el teñido de botones con la nueva versión (22.1) de la biblioteca de soporte que se lanzó el otro día.
Snild Dolkow

8
Puede usarlo colorButtonNormalcon AppCompat 22.1.1 (configurando el tema solo para los botones), me funciona en 4.4.4 y 5.1.
hunyadym

2
¿Alguna idea de cómo configurar lo mismo para TextView?
desarrollador de Android

8
En lugar de new ColorStateList(new int[][]{new int[0]}, new int[]{0xffffcc00});hacerlo, puede escribir de forma más concisa ColorStateList.valueOf(0xffffcc00);.
Ashkan Sarlak

5
Puede usar android.support.v7.widget.AppCompatButton con la aplicación: backgroundTint en el xml
Marcio Granzotto

30

Parece que teñir un dibujo ondulado no tiene sentido (y el fondo predeterminado de un botón es un dibujo ondulado).

De hecho, después de mirar el botón de dibujo predeterminado de la plataforma, encontré la forma "correcta" de hacer esto :. Tienes que definir esto en tu tema:

    <item name="android:colorButtonNormal">@color/accent</item>

(Por supuesto, esto es solo para nivel 21+).

Advertencia: dado que esto está definido en un tema, usará el color dado para todos los botones (al menos todos los botones en las actividades que usan ese tema).

Como beneficio adicional, también puede cambiar el color de la ondulación definiendo esto:

    <item name="android:colorControlHighlight">@color/accent_ripple</item>

colorControlHighlightSin embargo, cambiaría muchos otros widgets. Me alegro de que lo hayas resuelto.
natario

5
Puede aplicar esto a una vista individual definiendo un tema de superposición (por ejemplo, sin tema principal y solo un atributo definido) y utilizando el atributo android: theme.
Alanv

1
Entonces, ¿cómo se arregla para API 22 y posteriores? Además, este "error" ocurre solo en algunos dispositivos de API 21 (incluido nexus 5, galaxy s3)
vedant

22

Para resolver problemas relacionados con el teñido en Android 5.0.x, uso algo como esto:

public static void setButtonTint(Button button, ColorStateList tint) {
    if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP && button instanceof AppCompatButton) {
        ((AppCompatButton) button).setSupportBackgroundTintList(tint);
    } else {
        ViewCompat.setBackgroundTintList(button, tint);
    }
}

Utiliza el método de soporte solo para API 21 y ViewCompat para todos los demás casos.


@Marco Use:if (view instanceof TintableBackgroundView) { ((TintableBackgroundView) view).setSupportBackgroundTintList(tint); } else { ViewCompat.setBackgroundTintList(view, tint); }
chessdork

Esto no funciona con ImageButton en dispositivos anteriores a Lollipop.
toobsco42

Recibo una advertencia de pelusa cuando uso AppCompatButton.setSupportBackgroundTintList () AppCompatButton.setSupportBackgroundTintList solo se puede llamar desde el mismo grupo de bibliotecas (groupId = com.android.support)
starkej2

A mí me funcionó, pero tuve que invertir las condiciones.
Rodrigo Venancio

"solo se puede llamar desde el mismo grupo de bibliotecas (groupId = com.android.support" ¿por qué esta advertencia?
Ferran Negre

22

Normalmente lo hago dinámicamente usando PorterDuff:

mbutton = (Button) findViewById(R.id.mybutton);
mbutton.getBackground().setColorFilter(anycolor, PorterDuff.Mode.MULTIPLY);

Puede consultar diferentes modos de fusión aquí y buenos ejemplos aquí .


1
He usado PorterDuff.Mode.SRC y funciona perfectamente
francisco_ssb

Funciona perfectamente. En mi caso, quería usar el efecto de tinte en API 17, esto me ayudó.
ashishdhiman2007

2
Esta debería ser la respuesta aceptada. Confirme que trabaja en API 20.
hardanger

19

Solo use en app:backgroundTintlugar de android:backgroundTint, el tinte tendrá efecto debajo de Lollipop. El motivo es el AppCompatActivityuso AppCompatViewInflaterpara cambiar automáticamente Button o TextView a AppCompatButton o AppCompatTextView, y luego app:backgroundTintsurte efecto.

ingrese la descripción de la imagen aquí

En mi proyecto lo usé, funcionó.


9

Creo que necesitas ponerte android:backgrounda android:backgroundTinttrabajar.

Para ser más precisos, supongo que no se puede utilizar backgroundTintel fondo del botón predeterminado de los temas de Material, que se define como RippleDrawable.


1
Creo que es correcto. De hecho, encontré la forma "correcta" de hacer lo que quiero (ver mi respuesta).
BoD

3

Se informó un problema similar en google https://code.google.com/p/android/issues/detail?id=201873

Pero después del lanzamiento de la biblioteca de soporte de Android, revisión 23.2.1 (marzo de 2016), este error se solucionó.

Problema: FloatingActionButton.setBackgroundTintList (tinte @Nullable ColorStateList) ya no cambia el color de fondo

actualizar la biblioteca de soporte a Android Support Library to 23.2.1

Utilice la biblioteca de soporte de diseño (23.2.1) y appcompatwidgets como se muestra a continuación

Diseño de materiales para dispositivos de pre-piruleta :

AppCompat (también conocido como ActionBarCompat) comenzó como un backport de la API de ActionBar de Android 4.0 para dispositivos que se ejecutan en Gingerbread, proporcionando una capa de API común además de la implementación backportada y la implementación del marco. AppCompat v21 ofrece una API y un conjunto de funciones que está actualizado con Android 5.0


Biblioteca de compatibilidad de Android 22.1 :

La capacidad de teñir los widgets automáticamente cuando se usa AppCompat es increíblemente útil para mantener una marca sólida y una coherencia en toda la aplicación. Esto se hace automáticamente al inflar diseños, reemplazando Button con AppCompatButton, TextView con AppCompatTextView, etc. para garantizar que cada uno pueda admitir el teñido. En esta versión, esos widgets con reconocimiento de tinte ahora están disponibles públicamente, lo que le permite mantener la compatibilidad con tinte incluso si necesita subclasificar uno de los widgets compatibles.


3

Simplemente use la aplicación: backgroundTint en lugar de android: backgroundTint


2

Si miramos en el código fuente de la biblioteca de soporte, vemos que se tiñe normalmente son botones conocidos, pero si cambiamos la forma de nuestro botón (tengo un botón redondo), el tinte no funciona bien en api <= 21. También podemos ver que TintManager se convirtió en una clase pública (appcompat-v7: 23.1.1), por lo que podemos tomar ColorStateList de la forma del botón predeterminado (que está teñido correctamente en 5.0) para el tema actual (por lo que no tenemos que crear la matriz de colores):

    Context c = ...; // activity
    AppCompatButton ab = ...; // your button
    // works ok in 22+:
    if (Build.VERSION.SDK_INT <= 21) {
        // default appcompat button, that is tinted ok with current theme colors "abc_btn_default_mtrl_shape":
        // ColorStateList tint = TintManager.get(c).getTintList(R.drawable.abc_btn_default_mtrl_shape);
        // Appcompat 23.2 change:
        ColorStateList tint = AppCompatDrawableManager.get().getTintList(c, R.drawable.abc_btn_default_mtrl_shape);
        ab.setSupportBackgroundTintList(tint);
        }

desde appcompat 23.2 cambiaron la clase (¡aunque es pública!) TintManager -> AppCompatDrawableManager el código permanece casi igual
Pavel Biryukov

WTF ... getTintList cambió de público a protegido ahora; (necesita usar la reflexión :)
Pavel Biryukov

0

Porque el atributo backgroundTintsolo se usa en el nivel de API 21 y superior


Me doy cuenta de eso, y de hecho estoy probando en un dispositivo Lollipop. Actualizaré la pregunta para aclarar esto.
BoD

0

Tenga en cuenta que la biblioteca más actualizada de Recyclerview también puede causar este error.

Este comando

  sendBtnView.setBackgroundTintList(colorState)

funcionó perfectamente en el pasado pero dejó de funcionar para mí. después de la investigación, resulta que la causa es la biblioteca que se agregó a las dependencias de gradle:

  compile 'com.android.support:recyclerview-v7:+'

Así que intenté cambiarlo a 23.02.1 como se recomendó aquí en la publicación de Amit Vaghela. Me cambié a

  compile  'com.android.support:recyclerview-v7:23.02.1'

Pero el error de Gradle dijo que la biblioteca Recyclerview no tiene esta versión (23.02.1) (Gradle no pudo encontrarla en Jcenter raw.github o repositorio)

Luego, porque sabía que el comando setBackgroundTintList solía funcionar bien en el pasado con la versión 22.02.0 'en todas las otras bibliotecas que tengo en las dependencias de gradle. así que lo cambio a:

compile   'com.android.support:recyclerview-v7:22.02.0'

Y ahora vuelve a funcionar.


0

No estoy seguro de si se recomienda esto, pero puede probar esto:

Drawable newDrawable = mBtnAction.getBackground();  // obtain Bg drawable from the button as a new drawable
DrawableCompat.setTint(newDrawable, mActivity.getHomeTobBarBGColor());  //set it's tint
mBtnAction.setBackground(newDrawable);  //apply back to button

En un sentido general, funciona. Intenté, ViewCompatpero no parece funcionar correctamente.


0

puedes usar backgroundTint <android.support.design.button.MaterialButtoncon la "com.android.support:design:28.0.0-rc01"versión


0

Si está utilizando androidx, agregue la versión con prefijo y no con prefijo resuelto el problema en Android 5.1:

<style name="Button_Primary">
    <item name="android:layout_height">wrap_content</item>
    <item name="android:layout_width">wrap_content</item>
    <item name="android:backgroundTint">@color/button_primary_selector</item>
    <item name="backgroundTint">@color/button_primary_selector</item><!--needed for android 5-->
</style>

El selector button_primary está en la colorcarpeta con el siguiente contenido:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:local="http://schemas.android.com/apk/res-auto">
    <item android:state_enabled="true" android:color="@android:color/holo_blue_dark" />
    <item android:state_enabled="false" android:color="@android:color/darker_gray" />
</selector>

y aplicarlo en el botón regular en AppCompatActivity

<Button style="@style/Button_Primary"/>
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.