Cambiar el color "encendido" de un interruptor

156

Estoy usando un control Switch estándar con el tema holo.light en una aplicación ICS.

Quiero cambiar el color de estado resaltado o activado del botón de alternar del azul claro estándar al verde.

Esto debería ser fácil, pero parece que no puedo entender cómo hacerlo.

JamesSugrue
fuente
Realmente no veo otra manera que copiar los recursos de plataforma relevantes (selector y archivos * .png) y modificar el estado 'on' dibujable. No olvide señalar el Switchselector personalizado después.
MH.

Respuestas:

100

A partir de ahora, es mejor usar SwitchCompat de la biblioteca AppCompat.v7. Luego puede usar un estilo simple para cambiar el color de sus componentes.

values/themes.xml:

<style name="Theme.MyTheme" parent="Theme.AppCompat.Light">
    <!-- colorPrimary is used for the default action bar background -->
    <item name="colorPrimary">@color/my_awesome_color</item>

    <!-- colorPrimaryDark is used for the status bar -->
    <item name="colorPrimaryDark">@color/my_awesome_darker_color</item>

    <!-- colorAccent is used as the default value for colorControlActivated,
         which is used to tint widgets -->
    <item name="colorAccent">@color/accent</item>

    <!-- You can also set colorControlNormal, colorControlActivated
         colorControlHighlight, and colorSwitchThumbNormal. -->

</style>

ref: Blog de desarrolladores de Android

EDITAR :

La forma en que se debe aplicar correctamente es a través android:theme="@style/Theme.MyTheme" y también se puede aplicar a estilos primarios como EditTexts, RadioButtons, Switches, CheckBoxes y ProgressBars:

<style name="My.Widget.ProgressBar" parent="Widget.AppCompat.ProgressBar">

<style name="My.Widget.Checkbox" parent="Widget.AppCompat.CompoundButton.CheckBox">
Subordiente
fuente
1
Aunque no es aplicable en el momento, ¡esta debería ser la respuesta aceptada!
Andrew Gallasch
He cambiado esto a la respuesta aceptada, ya que parece el enfoque más "moderno" a esta pregunta.
JamesSugrue
1
Intenté todo esto y ninguno de ellos cambió el color del estado "encendido" para mi interruptor.
Adam Johns
31
'on' es colorAccent, 'off' es colorSwitchThumbNormal. Si usa el AppCompattema, debe usarlo en SwitchCompatlugar de hacerlo Switch. Si usa SDK 23+, puede usar android:thumbTinty android:thumbTintModecon a ColorStateList.
Tom
1
@ Tom PLZ respuesta será esos 'android: thumbTint' cosas van a funcionar en dispositivos <23
Shirish Herwade
269

Tarde para la fiesta, pero así es como lo hice

Estilo

 <style name="SCBSwitch" parent="Theme.AppCompat.Light">
        <!-- active thumb & track color (30% transparency) -->
        <item name="colorControlActivated">#46bdbf</item>

        <!-- inactive thumb color -->
        <item name="colorSwitchThumbNormal">#f1f1f1
        </item>

        <!-- inactive track color (30% transparency) -->
        <item name="android:colorForeground">#42221f1f
        </item>
    </style>

Colores

ingrese la descripción de la imagen aquí

Diseño

<android.support.v7.widget.SwitchCompat
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentRight="true"
    android:checked="false"
    android:theme="@style/SCBSwitch" />

Resultado

Ver cambio de colores para activar y desactivar interruptor

ingrese la descripción de la imagen aquí

Hitesh Sahu
fuente
14
@MaksimKniazev Tienes que usar SwitchCompat;)
Ovi Trif
1
Bien, excepto por colorControlActivated: no establece el color de la pista, solo el color del pulgar.
Puntero nulo el
1
Aquí hay una solución para Switch y SwitchCompat: stackoverflow.com/a/47036089/5869630
roghayeh hosseini
Las etiquetas <style> debían escribirse bajo res >> values ​​>> styles.xml y en la página XML para <Switch ...> solo debe agregar la línea llamada: android: theme = "@ style / SCBSwitch y mis colores son : colorControlActivated "> # ff0000 y colorSwitchThumbNormal"> # 00ff00 y android: colorForeground "> # 00ff00
Bay
@OviTrif ¡Impresionante! Es impresionante lo difícil que es encontrar una información simple como esa. Muchas y muchas respuestas que he estado leyendo, y nadie, dio una respuesta funcional hasta ahora. ¡Finalmente!
jairhumberto
49

Esto funciona para mí (requiere Android 4.1):

Switch switchInput = new Switch(this);
int colorOn = 0xFF323E46;
int colorOff = 0xFF666666;
int colorDisabled = 0xFF333333;
StateListDrawable thumbStates = new StateListDrawable();
thumbStates.addState(new int[]{android.R.attr.state_checked}, new ColorDrawable(colorOn));
thumbStates.addState(new int[]{-android.R.attr.state_enabled}, new ColorDrawable(colorDisabled));
thumbStates.addState(new int[]{}, new ColorDrawable(colorOff)); // this one has to come last
switchInput.setThumbDrawable(thumbStates);

Tenga en cuenta que el estado "predeterminado" debe agregarse al final como se muestra aquí.

El único problema que veo es que el "pulgar" del interruptor ahora parece más grande que el fondo o la "pista" del interruptor. Creo que es porque todavía estoy usando la imagen de pista predeterminada, que tiene un espacio vacío a su alrededor. Sin embargo, cuando intenté personalizar la imagen de la pista usando esta técnica, mi interruptor parecía tener una altura de 1 píxel con solo un fragmento del texto de encendido / apagado que aparecía. Debe haber una solución para eso, pero aún no la he encontrado ...

Actualización para Android 5

En Android 5, el código anterior hace que el interruptor desaparezca por completo. Deberíamos poder usar el nuevo setButtonTintList método , pero esto parece ignorarse para los modificadores. Pero esto funciona:

ColorStateList buttonStates = new ColorStateList(
        new int[][]{
                new int[]{-android.R.attr.state_enabled},
                new int[]{android.R.attr.state_checked},
                new int[]{}
        },
        new int[]{
                Color.BLUE,
                Color.RED,
                Color.GREEN
        }
);
switchInput.getThumbDrawable().setTintList(buttonStates);
switchInput.getTrackDrawable().setTintList(buttonStates);

Actualización para Android 6-7

Como Cheruby dijo en los comentarios, podemos usar lo nuevo setThumbTintListy funcionó como se esperaba para mí. También podemos usar setTrackTintList, pero eso aplica el color como una mezcla, con un resultado que es más oscuro de lo esperado en temas de color oscuro y más claro de lo esperado en temas de color claro, a veces hasta el punto de ser invisible. En Android 7, pude minimizar ese cambio anulando el modo de tinte de pista , pero no pude obtener resultados decentes en Android 6. Es posible que deba definir colores adicionales que compensen la fusión. (¿Alguna vez tiene la sensación de que Google no quiere que personalicemos la apariencia de nuestras aplicaciones?)

ColorStateList thumbStates = new ColorStateList(
        new int[][]{
                new int[]{-android.R.attr.state_enabled},
                new int[]{android.R.attr.state_checked},
                new int[]{}
        },
        new int[]{
                Color.BLUE,
                Color.RED,
                Color.GREEN
        }
);
switchInput.setThumbTintList(thumbStates);
if (Build.VERSION.SDK_INT >= 24) {
    ColorStateList trackStates = new ColorStateList(
            new int[][]{
                    new int[]{-android.R.attr.state_enabled},
                    new int[]{}
            },
            new int[]{
                    Color.GRAY,
                    Color.LTGRAY
            }
    );
    switchInput.setTrackTintList(trackStates);
    switchInput.setTrackTintMode(PorterDuff.Mode.OVERLAY);
}
arlomedia
fuente
Estoy usando el enfoque getThumbDrawable / getTrackDrawable para crear un interruptor donde ambos estados tienen el mismo color; en otras palabras, el interruptor no habilita / deshabilita algo, pero se usa para elegir entre dos alternativas.
Natix
44
Obtuve que DrawableCompat.setTintList le permitirá trabajar en dispositivos anteriores. Llamo a: DrawableCompat.setTintList (switchCompat.getThumbDrawable (), foregroundState);
Alexey
Edite la respuesta para incluir la solución DrawableCompat. Funciona perfectamente!
Dmytro Karataiev el
API 23+: también switchInput.setThumbTintList(buttonStates); funciona para Nougat. API 21-22: Use DrawableCompat como lo sugiere @Alexey. El switchInput.setButtonTintList(buttonStates);no funcionó para mí, que no colorear los estados para mi interruptor. API por debajo de 21: switchInput.getThumbDrawable().setColorFilter(someColor, PorterDuff.Mode.SrcIn); Esto funcionó para mí. También trabajé con Xamarin, así que traduzca esos a C # en los renderizadores de Android si usa Xamarin.Forms.
Cheruby
37

Para cambiar el estilo de Switch sin usar style.xml o código Java, puede personalizar el switch en XML de diseño:

<Switch
        android:id="@+id/checkbox"
        android:layout_width="wrap_content"
        android:thumbTint="@color/blue"
        android:trackTint="@color/white"
        android:checked="true"
        android:layout_height="wrap_content" />

Su atributo android: thumbTint y android: trackTint le permitieron personalizar el color.

Este es el resultado visual para este XML:

ingrese la descripción de la imagen aquí

Kevin ABRIOUX
fuente
17
Esto cambia el color del pulgar, sin importar si está activado o desactivado.
Desarrollador de Android
1
"El atributo thumbTint solo se usa en API nivel 21 y superior"
norbDEV
66
@norbDEV usa la aplicación: thumbTint y app: trackTint con SwitchCompat de la biblioteca AppCompat.v7 para un nivel API más bajo.
David Darias
Eso funciona, pero ¿qué pasa si desea cambiar el color del pulgar, dependiendo de si está activado o no?
TavernSenses
2
Si desea usar thumbTint debajo de 21, use en app:thumbTintlugar de android:thumbTinty cambie switchconSwitchCompat
Kavita_p
33

Cree un conmutador personalizado y anule setChecked para cambiar el color:

  public class SwitchPlus extends Switch {

    public SwitchPlus(Context context) {
        super(context);
    }

    public SwitchPlus(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public SwitchPlus(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public void setChecked(boolean checked) {
        super.setChecked(checked);
        changeColor(checked);
    }

    private void changeColor(boolean isChecked) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            int thumbColor;
            int trackColor;

            if(isChecked) {
                thumbColor = Color.argb(255, 253, 153, 0);
                trackColor = thumbColor;
            } else {
                thumbColor = Color.argb(255, 236, 236, 236);
                trackColor = Color.argb(255, 0, 0, 0);
            }

            try {
                getThumbDrawable().setColorFilter(thumbColor, PorterDuff.Mode.MULTIPLY);
                getTrackDrawable().setColorFilter(trackColor, PorterDuff.Mode.MULTIPLY);
            }
            catch (NullPointerException e) {
                e.printStackTrace();
            }
        }
    }
}
francisco_ssb
fuente
2
La primera publicación que realmente me ayudó a lograr un color personalizado para el cambio de material sin usar estilo o temas. Gracias !
Mackovich el
1
Agradable. Ya tenía mi propio Switch personalizado, así que solo tuve que anular el método setChecked y todos cambiaron automáticamente sus colores. Gracias desde españa.
Julio
22

Si bien la respuesta de SubChord es correcta, en realidad no responde a la pregunta de cómo configurar el color "activado" sin afectar también a otros widgets. Para hacer esto, use a ThemeOverlayen styles.xml:

<style name="ToggleSwitchTheme" parent="ThemeOverlay.AppCompat.Light">
    <item name="colorAccent">@color/green_bright</item>
</style>

Y consúltalo en tu interruptor:

<android.support.v7.widget.SwitchCompat
  android:theme="@style/ToggleSwitchTheme" ... />

Al hacerlo, SOLO afectará el color de las vistas a las que desea aplicarlo.

Greg Ennis
fuente
Por alguna razón, también tuve que establecer "colorControlActivated" en el mismo valor, pero en POC, fue suficiente para usar "colorAccent". ¿Cómo?
Desarrollador de Android
22
<androidx.appcompat.widget.SwitchCompat
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:thumbTint="@color/white"
                app:trackTint="@drawable/checker_track"/>

Y dentro de checker_track.xml:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="@color/lightish_blue" android:state_checked="true"/>
    <item android:color="@color/hint" android:state_checked="false"/>
</selector>
equipo de trabajo
fuente
thumbTintsolo se aplica en Android API 21 y superior. ¿Cómo si quiero cambiar el color debajo de Android 21?
Giovanka Bisano
developer.android.com/reference/android/support/v7/widget/… SwitchCompat es compatible con versiones anteriores de API 7 y superior
equipo de equipo
1
Es 2020. Realmente me pregunto en qué parte del mundo la gente sigue usando Android 21 y versiones anteriores.
zeeshan
18

Lo resolví actualizando el filtro de color cuando se cambió el estado del interruptor ...

public void bind(DetailItem item) {
    switchColor(item.toggle);
    listSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
                switchColor(b);
        }
    });
}

private void switchColor(boolean checked) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
        listSwitch.getThumbDrawable().setColorFilter(checked ? Color.BLACK : Color.WHITE, PorterDuff.Mode.MULTIPLY);
        listSwitch.getTrackDrawable().setColorFilter(!checked ? Color.BLACK : Color.WHITE, PorterDuff.Mode.MULTIPLY);
    }
}
MCR
fuente
13

Puede ser un poco tarde, pero para los botones de cambio, el botón toogle no es la respuesta, debe cambiar el dibujo en el parámetro xml del cambio:

 android:thumb="your drawable here"
Golgorz
fuente
9

hacer dibujable "newthumb.xml"

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="@color/Green" android:state_checked="true"/>
    <item android:color="@color/Red" android:state_checked="false"/>
</selector>

y hacer dibujable "newtrack.xml"

<selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:color="@color/black" android:state_checked="true"/>
        <item android:color="@color/white" android:state_checked="false"/>
    </selector>

y agregarlo en Switch:

<Switch
        android:trackTint="@drawable/newtrack"
        android:thumbTint="@drawable/newthumb"
         />
مهند عطية
fuente
1
Esto funciona. Sin embargo, debe tenerse en cuenta que AndroidStudio no podrá sugerir recursos @drawable para trackTinto thumbTint. Uno necesita escribirlo manualmente y funciona.
Benjamin Basmaci
Por alguna razón, esta es la única respuesta que funciona de manera confiable en mi Huawei. ¡Gracias!
einUsername
7

En Android Lollipop y superior, defínalo en el estilo de tu tema:

<style name="BaseAppTheme" parent="Material.Theme">
    ...
    <item name="android:colorControlActivated">@color/color_switch</item>
</style>
emen
fuente
El problema con esta solución es que también cambia los colores de mis mensajes de texto seleccionados, que no es lo que quiero.
codewing
@codewing Por supuesto que lo hará. Porque esto se establece en la preferencia de estilo global. Para lograr su objetivo, es encontrar el id de vista de su vista de destino y modificar sus atributos.
emen
OK, eso es para la posición "On". ¿Qué pasa con el cambio del color del pulgar para la posición "Off"?
TavernSenses
7

Cree su propia imagen de 9 parches y configúrela como fondo del botón de alternar.

http://radleymarx.com/2011/simple-guide-to-9-patch/

you786
fuente
2
Sí, podría hacer eso, pero seguramente DEBE haber una manera más fácil. ¿Selectores tal vez?
JamesSugrue
No, no hay forma más fácil. No puedes cambiar mágicamente el color de una imagen :)
you786
Buen punto. No entendí completamente cómo funcionaba hasta que tuve una mirada más profunda.
JamesSugrue
@Denizen, ¿estás seguro? Si es así, publique una respuesta y la votaré.
you786
@Denizen Por favor, elimine su comentario. Android Switch siempre devuelve nulo para getBackground (), perdí 30 minutos intentando esto.
Shirish Herwade
5

La solución sugerida de arlomedia funcionó para mí. Sobre su problema de espacio extra resolví quitar todos los rellenos del interruptor.

EDITAR

Según lo solicitado, aquí lo que tengo.

En el archivo de diseño, mi interruptor está dentro de un diseño lineal y después de un TextView.

<LinearLayout
        android:id="@+id/myLinearLayout"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_gravity="center_horizontal|center"
        android:gravity="right"
        android:padding="10dp"
        android:layout_marginTop="0dp"
        android:background="@drawable/bkg_myLinearLayout"
        android:layout_marginBottom="0dp">
        <TextView
            android:id="@+id/myTextForTheSwitch"
            android:layout_height="wrap_content"
            android:text="@string/TextForTheSwitch"
            android:textSize="18sp"
            android:layout_centerHorizontal="true"
            android:layout_gravity="center_horizontal|center"
            android:gravity="right"
            android:layout_width="wrap_content"
            android:paddingRight="20dp"
            android:textColor="@color/text_white" />
        <Switch
            android:id="@+id/mySwitch"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textOn="@string/On"
            android:textOff="@string/Off"
            android:layout_centerHorizontal="true"
            android:layout_gravity="center_horizontal"
            android:layout_toRightOf="@id/myTextForTheSwitch"
            android:layout_alignBaseline="@id/myTextForTheSwitch"
            android:gravity="right" />
    </LinearLayout>

Como estoy trabajando con Xamarin / Monodroid (min. Android 4.1) mi código es:

Android.Graphics.Color colorOn = Android.Graphics.Color.Green;
Android.Graphics.Color colorOff = Android.Graphics.Color.Gray;
Android.Graphics.Color colorDisabled = Android.Graphics.Color.Green;

StateListDrawable drawable = new StateListDrawable();
drawable.AddState(new int[] { Android.Resource.Attribute.StateChecked }, new ColorDrawable(colorOn));
drawable.AddState(new int[] { -Android.Resource.Attribute.StateEnabled }, new ColorDrawable(colorDisabled));
drawable.AddState(new int[] { }, new ColorDrawable(colorOff));

swtch_EnableEdit.ThumbDrawable = drawable;

swtch_EnableEdit se definió anteriormente de esta manera (Xamarin):

Switch swtch_EnableEdit = view.FindViewById<Switch>(Resource.Id.mySwitch);

No configuro en todos los rellenos y no llamo .setPadding (0, 0, 0, 0).

Daniele D.
fuente
¿Puedes proporcionar un código para eso? Intenté switchInput.setPadding (0, 0, 0, 0) pero nada cambió.
arlomedia
1
Probado en Xamarin usando la biblioteca AppCompat para apuntar a 5.xy esto funcionó como se anuncia.
Alex.Ritna
4

puede hacer un estilo personalizado para el widget de cambio que usa el acento de color como predeterminado cuando lo hace con un estilo personalizado

<style name="switchStyle" parent="Theme.AppCompat.Light">
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorPrimary</item>    <!-- set your color -->
</style>    
yousef
fuente
1

Intente encontrar la respuesta correcta aquí: Selector en el color de fondo de TextView . En dos palabras, debe crear Shape en XML con color y luego asignarlo al estado "marcado" en su selector.

Shamm
fuente
Buena solución, pero ¿sabes cómo podemos cambiar el color dinámicamente?
inverted_index
Solo necesita configurar el selector como recurso de fondo
Shamm
1

No sé cómo hacerlo desde Java, pero si tiene un estilo definido para su aplicación, puede agregar esta línea en su estilo y tendrá el color deseado para mí, he usado # 3F51B5

<color name="ascentColor">#3F51B5</color>
erluxman
fuente
1

La forma más fácil es definir el tinte de la pista y establecer el modo de tinte en src_over para eliminar el 30% de transparencia.

android:trackTint="@drawable/toggle_style"
android:trackTintMode="src_over"

toggle_style.xml

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="@color/informationDefault"
        android:state_checked="true"
        />
    <item android:color="@color/textDisabled" android:state_checked="false"/>
</selector>
Ege Kuzubasioglu
fuente
0

Como una adición a las respuestas existentes: puede personalizar el pulgar y la pista usando selectores en la res/colorcarpeta, por ejemplo:

switch_track_selector

<?xml version="1.0" encoding="utf-8"?>
<selector
    xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="@color/lightBlue"
        android:state_checked="true" />
    <item android:color="@color/grey"/>
</selector>

switch_thumb_selector

<selector
    xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="@color/darkBlue"
        android:state_checked="true" />
    <item android:color="@color/white"/>
</selector>

Use estos selectores para personalizar pistas y tintes de pulgar:

<androidx.appcompat.widget.SwitchCompat
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:trackTint="@color/switch_track_selector"
    app:thumbTint="@color/switch_thumb_selector"/>

Tenga en cuenta que si usa standart Switchy androidespacio de nombres para estos atributos, solo funcionará para API 23 y posterior, así que use SwitchCompatcon appespacio de nombresxmlns:app="http://schemas.android.com/apk/res-auto" como solución universal.

Resultado:

ingrese la descripción de la imagen aquí

permanecer4vida
fuente
0

En xml, puede cambiar el color como:

 <androidx.appcompat.widget.SwitchCompat
    android:id="@+id/notificationSwitch"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:checked="true"
    app:thumbTint="@color/darkBlue"
    app:trackTint="@color/colorGrey"/>

Dinámicamente puedes cambiar como:

Switch.thumbDrawable.setColorFilter(ContextCompat.getColor(requireActivity(), R.color.darkBlue), PorterDuff.Mode.MULTIPLY)
LIEN ROHIT
fuente
-1

Solución para Android Studio 3.6:

yourSwitch.setTextColor(getResources().getColor(R.color.yourColor));

Cambia el color del texto de un valor definido en el archivo XML de color (yourColor).

ChristianYami
fuente