我的应用程序中有一些具有不同颜色的开关控件,为了更改它们的颜色,我使用了多个自定义可绘制选择器。
随着 AppCompat v21 库的发布,引入了新的 android.support.v7.widget.SwitchCompat 控件。
是否可以在没有客户可绘制选择器但使用 XML 或代码的情况下以编程方式更改 SwitchCompat 的颜色?
我的应用程序中有一些具有不同颜色的开关控件,为了更改它们的颜色,我使用了多个自定义可绘制选择器。
随着 AppCompat v21 库的发布,引入了新的 android.support.v7.widget.SwitchCompat 控件。
是否可以在没有客户可绘制选择器但使用 XML 或代码的情况下以编程方式更改 SwitchCompat 的颜色?
首先,您应该看看那里的 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"/>
感谢 vine'th,我通过一个指向 SO 答案的链接完成了我的答案,该链接解释了如何在 Switch 关闭时指定轨道的前景,它就在那里。
好的,很抱歉,但这些答案中的大多数都不完整或有一些小错误。@austyn-mahoney 的非常完整的答案是正确的,并且是该答案的来源,但它很复杂,您可能只想设置一个开关的样式。跨不同版本的 Android 的“样式”控件是一个史诗般的痛苦。在一个设计约束非常严格的项目中拔掉头发几天后,我终于崩溃并编写了一个测试应用程序,然后真正深入研究并测试了样式开关和复选框的各种解决方案,因为当一个设计有一个它经常有另一个。这是我发现的...
第一:您实际上不能为其中任何一个设置样式,但您可以将一个主题应用于所有这些,或者只是其中一个。
第二:您可以从 XML 中完成所有操作,并且不需要第二个 values-v21/styles.xml。
第三:在开关方面,如果您想支持旧版本的 Android,您有两个基本选择(我相信您会这样做)......
SwitchCompat
并且您将能够使其在不同平台上看起来相同。Switch
并且你可以用你的主题的其余部分来设置它的主题,或者只是那个特定的开关,在旧版本的 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_18:
我认为下面链接中的答案更好
<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>
所以有些日子我缺乏脑细胞并且:
<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 的回答
为了更好地控制轨道颜色(没有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
文件中。
小心 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 上什么都不需要
我同时使用 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>
<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>
只是
android:buttonTint="@color/primary"