共计 3308 个字符,预计需要花费 9 分钟才能阅读完成。
在 Android 款式零碎系列的前几篇文章中,咱们介绍了主题背景与款式的区别,以及为什么说通过主题背景和公共主题背景属性来合成您要实现的内容是一个不错的主见,请点击链接回顾:
- Android 款式零碎 | 主题背景和款式
- Android 款式零碎 | 常见的主题背景属性
这会让咱们通过创立更少的布局或款式,以隔离主题背景中的批改。在理论开发中,您通常心愿依据主题背景扭转色彩,因而您应该始终通过主题背景属性来援用色彩。
这意味着您能够将如下代码视为有代码异味 (Code smell):
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<View …
android:background="@color/white"/>
相同,您应该应用主题背景属性,它容许您按主题更改色彩,例如,在 深色主题 中提供一个不同的值:
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<View …
android:background="?attr/colorSurface"/>
即便您以后不反对其余主题 (什么,您的利用还没有反对深色主题?),咱们仍然建议您采纳这种办法,因为这样会让新主题的采纳变得更加简略。
合格的 Colors 文件
您能够通过在不同的配置中增加不同的值来扭转色彩 (例如,在 res/values/colors.xml 中和在 res/values-night/colors.xml 中的备选值里均定义 @color/foo),但咱们仍然建议您应用主题背景属性来代替它们。对色彩层级的辨别,会迫使您给色彩赋予语义化名称,换句话说,您应该不会在给色彩命名为 @color/white 的同时,又为深色模式提供一个深色变体,这会让人感到十分困惑。所以,您可能会想要应用一个语义化名称,例如 @color/background。这种办法带来的问题是它合并了色彩申明和具体的值,因而,它并没有指出色彩是能够或者可能随主题背景而变动的。
@colors 的变动也会激励您发明更多色彩。如果在不同的情境下要应用具备雷同值的、新的语义化命名的色彩 (即,不是背景色但应该应用雷同色彩),这时候您仍须要在 colors 文件中创立新的条目。通过应用主题背景属性,咱们能够将语义色彩的申明从提供它们的值中辨别开来,而且让应用方更分明地理解到色彩会随主题背景而变动 (因为它们应用 ?attr/ 语法)。将色彩申明放弃为字面值,您就能够自定义利用应用的色彩调色板,并在主题背景级别批改它们,这会让 color.xml 较小且易保护。
这种办法的额定益处是,布局 / 款式援用这些色彩时复用性变得更高。因为主题背景能够被笼罩或者扭转,因而这间接示意: 您不须要创立其余布局或款式就能够更改某些色彩——您能够在雷同的布局中应用不同的主题背景。
始终应用?
在某些状况下,您或者不想依照主题背景更改色彩。例如,在 Material Design 标准文档 中提到,您可能心愿在浅色和深色主题中均应用同一类型的色彩。
在这种非凡状况下,间接援用色彩资源是再适合不过的:
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<FloatingActionButton …
app:backgroundTint="@color/owl_pink_500"/>
以后倒退情况
当应用 ColorStateLists 时,您可能也不会在您的布局 / 款式中间接援用主题背景属性。
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<View …
android:background="@color/primary_20"/>
如果 primary_20 是一个 ColorStateList,它自身援用主题背景属性来获取色值也可能是正当的 (请参见下文)。ColorStateLists 通常为不同的状态 (按下,禁用等) 提供不同的色彩,但它还有另外一种可用于主题化性能您可在选取的色彩上指定透明度值:
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<selector …
<item android:alpha="0.20" android:color="?attr/colorPrimary" />
</selector>
这种单项 ColorStateList (即只提供单个默认色彩,而非每种状态的不同色彩) 有助于缩小您须要保护的色彩资源数量。它并没有定义一个新的色彩资源的形式来手动为您 (每一个配置文件) 的 primary 色彩设置 alpha 值,而是通过扭转以后主题背景中的 colorPrimary 的形式。如果您的原始色彩产生了变动,则只须要在一个中央进行更新,无需调整所有已更新的中央。
尽管此技术很有用,但仍有一些注意事项:
- 如果指定的色彩也具备 alpha 值,则 alpha 会被合并。例如,将 50% 的 alpha 利用于 50% 的不通明红色中,将产生 25% 的红色:
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<selector …
<item android:alpha="0.50" android:color="#80ffffff" />
</selector>
因而,最好将主题背景色彩指定为齐全不通明,而后应用 ColorStateLists 批改它们的 alpha。
- 仅在 API 23 中增加了 alpha 组件,因而,如果您的最小 sdk 低于这个版本,请确保应用反对此行为的 AppCompatResources.getColorStateList) (并始终应用 android:alpha 命名空间,而绝不应用 app:alpha 命名空间)。
- 通常,咱们应用简写法,将色彩设置为 Drawable,例如:
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<View …
android:background="@color/foo"/>
View 的背景是一个 Drawable,此简写把给定的色彩强转成了一个 ColorDrawable。然而没有方法把 ColorStateList 转换成 Drawable (API 29 之前应用 ColorStateListDrawable 解决这个问题)。
然而,咱们能够通过曲折的形式绕过此限度:
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<View …
android:background="@drawable/a_solid_white_rectangle_shape_drawable"
app:backgroundTint="@color/some_color_state_list"/>
请确保您的 backgroundTint 反对您的 View 所需的状态,例如,如果被禁用时须要更改。
强制执行
即便您曾经压服本人应用主题背景属性和 ColorStateList,但如何在代码库或者团队中应用呢?您能够在 Code review 期间尝试保持警惕,但它的扩展性不是很好。更好的办法是依附工具来解决此问题。
[《Making Android Lint Theme Aware》](https://proandroiddev.com/mak…
) 这篇文章简述了如何通过增加 Lint 查看来寻找间接援用色彩的用法,并涵盖了文中提及到的所有倡议。
间接应用
应用主题背景属性和 ColorStateList 将色彩合成为主题背景的办法,可使您的布局和款式更加灵便,进步代码复用性并放弃代码库的精简和易维护性。
咱们将在后续文章中介绍更多主题背景的用法以及它们之间的相互影响,感兴趣的读者请持续关注。