150

我的应用程序中有一些具有不同颜色的开关控件,为了更改它们的颜色,我使用了多个自定义可绘制选择器。

随着 AppCompat v21 库的发布,引入了新的 android.support.v7.widget.SwitchCompat 控件。

是否可以在没有客户可绘制选择器但使用 XML 或代码的情况下以编程方式更改 SwitchCompat 的颜色?

4

9 回答 9

351

AppCompat 着色属性:

首先,您应该看看那里的 appCompat lib 文章以及您可以设置的不同属性:

colorPrimary:应用程序的主要品牌颜色。默认情况下,这是应用于操作栏背景的颜色。

colorPrimaryDark:主要品牌颜色的深色变体。默认情况下,这是应用于状态栏(通过 statusBarColor)和导航栏(通过 navigationBarColor)的颜色。

colorAccent:对主要品牌颜色的明亮补充。默认情况下,这是应用于框架控件的颜色(通过 colorControlActivated)。

colorControlNormal:在正常状态下应用于框架控件的颜色。

colorControlActivated:应用于处于激活(例如选中、打开)状态的框架控件的颜色。

colorControlHighlight:应用于框架控件突出显示的颜色(例如涟漪、列表选择器)。

colorButtonNormal:在正常状态下应用于框架按钮的颜色。

colorSwitchThumbNormal:在正常状态下应用于框架开关拇指的颜色。(关掉)


如果单个活动中的所有自定义开关都相同:

使用以前的属性,您可以为每个活动定义自己的主题:

<style name="Theme.MyActivityTheme" 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>

和 :

<manifest>
...
    <activity
        android:name=".MainActivity" 
        android:theme="@style/Theme.MyActivityTheme">
    </activity>
...
</manifest>

如果您想在单个活动中使用不同的自定义开关:

由于 appcompat 中的小部件着色通过拦截任何布局膨胀并在其位置插入小部件的特殊色调感知版本来工作(参见 Chris Banes的帖子),因此您不能将自定义样式应用于布局 xml 文件的每个开关。您必须设置一个自定义上下文,该上下文将使用正确的颜色进行着色切换。

--

要为pre-5.0执行此操作,您需要创建一个覆盖全局主题和自定义属性的上下文,然后以编程方式创建您的开关:

ContextThemeWrapper ctw = ContextThemeWrapper(getActivity(), R.style.Color1SwitchStyle); 
SwitchCompat sc = new SwitchCompat(ctw)

从 AppCompat 开始v22.1,您可以使用以下XML方法将主题应用于开关小部件:

<RelativeLayout
    xmlns:app="http://schemas.android.com/apk/res-auto"
    ...>

    <android.support.v7.widget.SwitchCompat
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:theme="@style/Color1SwitchStyle"/>

您的自定义开关主题:

<style name="Color1SwitchStyle">
    <item name="colorControlActivated">@color/my_awesome_color</item>
</style>

--

Android 5.0上,它看起来像是一个新的视图属性:(android:theme与清单中的活动声明相同)。基于另一个 Chris Banes帖子,使用后者,您应该能够直接在布局 xml 的视图上定义自定义主题:

<android.support.v7.widget.SwitchCompat
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:theme="@style/Color1SwitchStyle"/>

更改 SwitchCompat 的轨道颜色

感谢 vine'th,我通过一个指向 SO 答案的链接完成了我的答案,该链接解释了如何在 Switch 关闭时指定轨道的前景,它就在那里

于 2014-11-03T13:09:14.197 回答
76

好的,很抱歉,但这些答案中的大多数都不完整或有一些小错误。@austyn-mahoney 的非常完整的答案是正确的,并且是该答案的来源,但它很复杂,您可能只想设置一个开关的样式。跨不同版本的 Android 的“样式”控件是一个史诗般的痛苦。在一个设计约束非常严格的项目中拔掉头发几天后,我终于崩溃并编写了一个测试应用程序,然后真正深入研究并测试了样式开关和复选框的各种解决方案,因为当一个设计有一个它经常有另一个。这是我发现的...

第一:您实际上不能为其中任何一个设置样式,但您可以将一个主题应用于所有这些,或者只是其中一个。

第二:您可以从 XML 中完成所有操作,并且不需要第二个 values-v21/styles.xml。

第三:在开关方面,如果您想支持旧版本的 Android,您有两个基本选择(我相信您会这样做)......

  1. 您可以使用 aSwitchCompat并且您将能够使其在不同平台上看起来相同。
  2. 你可以使用 aSwitch并且你可以用你的主题的其余部分来设置它的主题,或者只是那个特定的开关,在旧版本的 Android 上你只会看到一个没有样式的旧方形开关。

好的,现在是简单的参考代码。如果您再次创建一个简单的 Hello World!并将此代码放入您可以尽情玩耍。所有这些都是样板,所以我将包含活动和样式的 XML...

活动主.xml...

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.kunai.switchtest.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="'Styled' SwitchCompat" />

    <android.support.v7.widget.SwitchCompat
        android:id="@+id/switch_item"
        android:layout_width="wrap_content"
        android:layout_height="46dp"
        android:layout_alignParentEnd="true"
        android:layout_marginEnd="16dp"
        android:checked="true"
        android:longClickable="false"
        android:textOff="OFF"
        android:textOn="ON"
        app:switchTextAppearance="@style/BrandedSwitch.text"
        app:theme="@style/BrandedSwitch.control"
        app:showText="true" />

</RelativeLayout>

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.kunai.switchtest.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Themed SwitchCompat" />

    <android.support.v7.widget.SwitchCompat
        android:id="@+id/switch_item2"
        android:layout_width="wrap_content"
        android:layout_height="46dp"
        android:layout_alignParentEnd="true"
        android:layout_marginEnd="16dp"
        android:checked="true"
        android:longClickable="false" />

</RelativeLayout>

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.kunai.switchtest.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Themed Switch" />

    <Switch
        android:id="@+id/switch_item3"
        android:layout_width="wrap_content"
        android:layout_height="46dp"
        android:layout_alignParentEnd="true"
        android:layout_marginEnd="16dp"
        android:checked="true"
        android:longClickable="false"
        android:textOff="OFF"
        android:textOn="ON"/>

</RelativeLayout>

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.kunai.switchtest.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="'Styled' Switch" />

    <Switch
        android:id="@+id/switch_item4"
        android:layout_width="wrap_content"
        android:layout_height="46dp"
        android:layout_alignParentEnd="true"
        android:layout_marginEnd="16dp"
        android:checked="true"
        android:longClickable="false"
        android:textOff="OFF"
        android:textOn="ON"
        android:theme="@style/BrandedSwitch"/>

</RelativeLayout>

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.kunai.switchtest.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="'Styled' CheckBox" />

    <CheckBox
        android:id="@+id/checkbox"
        android:layout_width="wrap_content"
        android:layout_height="46dp"
        android:layout_alignParentEnd="true"
        android:layout_marginEnd="16dp"
        android:checked="true"
        android:longClickable="false"
        android:theme="@style/BrandedCheckBox"/>

</RelativeLayout>

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.kunai.switchtest.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Themed CheckBox" />

    <CheckBox
        android:id="@+id/checkbox2"
        android:layout_width="wrap_content"
        android:layout_height="46dp"
        android:layout_alignParentEnd="true"
        android:layout_marginEnd="16dp"
        android:checked="true"
        android:longClickable="false"/>

</RelativeLayout>

样式.xml...

<resources>

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">#3F51B5</item>
    <item name="colorPrimaryDark">#303F9F</item>
    <item name="colorAccent">#FF4081</item>
</style>

<style name="BrandedSwitch.control" parent="Theme.AppCompat.Light">
    <!-- active thumb & track color (30% transparency) -->
    <item name="colorControlActivated">#e6e600</item>
    <item name="colorSwitchThumbNormal">#cc0000</item>
</style>

<style name="BrandedSwitch.text" parent="Theme.AppCompat.Light">
    <item name="android:textColor">#ffa000</item>
    <item name="android:textSize">9dp</item>
</style>

<style name="BrandedCheckBox" parent="AppTheme">
    <item name="colorAccent">#aaf000</item>
    <item name="colorControlNormal">#ff0000</item>
</style>

<style name="BrandedSwitch" parent="AppTheme">
    <item name="colorAccent">#39ac39</item>
</style>

我知道,我知道,你懒得构建这个,你只想让你的代码编写并签入,这样你就可以关闭这个痛苦的 Android 兼容性噩梦错误,这样你团队中的设计师最终会很开心. 我得到它。这是你运行它时的样子......

API_21:

API 21

API_18:

API18

于 2016-07-20T00:47:51.000 回答
18

我认为下面链接中的答案更好

如何更改 SwitchCompat 的轨道颜色

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
   ...
   <!-- Active thumb color & Active track color(30% transparency) -->
   <item name="colorControlActivated">@color/theme</item>
   <!-- Inactive thumb color -->
   <item name="colorSwitchThumbNormal">@color/grey300</item>
   <!-- Inactive track color(30% transparency) -->
   <item name="android:colorForeground">@color/grey600</item>
   ...
</style>
于 2015-11-04T18:06:42.647 回答
11

所以有些日子我缺乏脑细胞并且:

<android.support.v7.widget.SwitchCompat
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        style="@style/CustomSwitchStyle"/>

不应用主题,因为样式不正确。我应该使用 app:theme :P

<android.support.v7.widget.SwitchCompat
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:theme="@style/CustomSwitchStyle"/>

哎呀。这篇文章让我深入了解了我的错误......希望如果有人偶然发现它会像我一样帮助他们。谢谢 Gaëtan Maisse 的回答

于 2015-06-26T13:13:42.380 回答
5

为了更好地控制轨道颜色(没有API受控的 alpha 变化),我以编程方式扩展SwitchCompat和设置元素的样式:

    public class CustomizedSwitch extends SwitchCompat {

    public CustomizedSwitch(Context context) {
        super(context);
        initialize(context);
    }

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

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

    public void initialize(Context context) {
        // DisplayMeasurementConverter is just a utility to convert from dp to px and vice versa
        DisplayMeasurementConverter displayMeasurementConverter = new DisplayMeasurementConverter(context);
        // Sets the width of the switch
        this.setSwitchMinWidth(displayMeasurementConverter.dpToPx((int) getResources().getDimension(R.dimen.tp_toggle_width)));
        // Setting up my colors
        int mediumGreen = ContextCompat.getColor(context, R.color.medium_green);
        int mediumGrey = ContextCompat.getColor(context, R.color.medium_grey);
        int alphaMediumGreen = Color.argb(127, Color.red(mediumGreen), Color.green(mediumGreen), Color.blue(mediumGreen));
        int alphaMediumGrey = Color.argb(127, Color.red(mediumGrey), Color.green(mediumGrey), Color.blue(mediumGrey));
        // Sets the tints for the thumb in different states
        DrawableCompat.setTintList(this.getThumbDrawable(), new ColorStateList(
                new int[][]{
                        new int[]{android.R.attr.state_checked},
                        new int[]{}
                },
                new int[]{
                        mediumGreen,
                        ContextCompat.getColor(getContext(), R.color.light_grey)
                }));
        // Sets the tints for the track in different states
        DrawableCompat.setTintList(this.getTrackDrawable(), new ColorStateList(
                new int[][]{
                        new int[]{android.R.attr.state_checked},
                        new int[]{}
                },
                new int[]{
                        alphaMediumGreen,
                        alphaMediumGrey
                }));
    }
}

每当我想使用 时CustomizedSwitch,我只需将一个添加到我的xml文件中。

于 2017-09-06T10:31:48.620 回答
2

小心 SwitchCompat 的已知错误

这是 AppCompat https://code.google.com/p/android/issues/detail?id=78262上 drawable-hdpi 中文件损坏的错误

要修复它,只需用这两个文件覆盖它 https://github.com/lopespm/quick-fix-switchcompat-resources 将它添加到您的目录中 drawable-hdpi

XML

<android.support.v7.widget.SwitchCompat
android:id="@+id/dev_switch_show_dev_only"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>

在 Java 上什么都不需要

于 2015-01-06T16:49:45.217 回答
2

我同时使用 style 和 android:theme 的工作示例(API >= 21)

<android.support.v7.widget.SwitchCompat
    android:id="@+id/wan_enable_nat_switch"
    style="@style/Switch"
    app:layout_constraintBaseline_toBaselineOf="@id/wan_enable_nat_label"
    app:layout_constraintEnd_toEndOf="parent" />

<style name="Switch">
    <item name="android:layout_width">wrap_content</item>
    <item name="android:layout_height">wrap_content</item>
    <item name="android:paddingEnd">16dp</item>
    <item name="android:focusableInTouchMode">true</item>
    <item name="android:theme">@style/ThemeOverlay.MySwitchCompat</item>
</style>

<style name="ThemeOverlay.MySwitchCompat" parent="">
    <item name="colorControlActivated">@color/colorPrimaryDark</item>
    <item name="colorSwitchThumbNormal">@color/text_outline_not_active</item>
    <item name="android:colorForeground">#42221f1f</item>
</style>
于 2019-01-23T09:00:15.023 回答
0
<android.support.v7.widget.SwitchCompat
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/adamSwitch"
    android:textColor="@color/top_color"
    android:textAppearance="@color/top_color"
    android:gravity="center"
    app:showText="true"
    app:theme="@style/Custom.Widget.SwitchCompat"
    app:switchPadding="5dp"
    />

在 style.xml 中

<style name="Custom.Widget.SwitchCompat" parent="Widget.AppCompat.CompoundButton.Switch" >
            <item name="android:textColorPrimary">@color/blue</item>  <!--textColor on activated state -->
      </style>
于 2015-11-11T10:02:35.057 回答
-4

只是

 android:buttonTint="@color/primary"
于 2018-07-06T10:32:16.683 回答