Android开发

【译】Android Styling 4: 主题实战

本文主要是介绍【译】Android Styling 4: 主题实战,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

原文:Android Styling: Themes Overlay
作者:Nick Butcher
译者:Fly_with24


题图来自 Virginia Poltrack


在 Android styling 系列文章中,我们研究了 style 与 theme 的区别,讨论了 使用主题和主题属性的优势,并且介绍了 常用的属性


今天,我们将集中讨论主题的实际使用,如何将其应用到您的应用程序中

范围

在 第一篇文章 中我们提到

Theme 可以作为 Context 的属性被获取,并且它可以从任何 Context 或 Context 的子类获得,例如 ActivityView,或者 ViewGroup。这些对象存在于一个「树」中,其中 Activity 包含 ViewGroup,ViewGroup 包含 View。在此树的任何级别上指定主题都会影响到其后代节点,例如在 ViewGroup 上设置 Theme 会作用域其所有子 View(这与只作用于单一 View 的 Style 相反)

在此「树」中的任何一层设置主题都不会 「替换 」当前有效的主题,而是将其 「覆盖」。下面的例子中有一个按钮,该按钮可以选择一个主题,但它的 parent 也可以指定一个主题:

<!-- Copyright 2019 Google LLC.	
   SPDX-License-Identifier: Apache-2.0 -->
<ViewGroup …
  android:theme="@style/Theme.App.Foo">
  <Button …
    android:theme="@style/Theme.App.Bar"/>
</ViewGroup>
复制代码

如果在两个主题中都指定了属性,则最本地的 「获胜」,即 主题Bar 将应用于按钮。 在主题 Foo 中指定但 在主题 Bar 中指定的任何属性也将应用于按钮

Themes overlay each other

这可能看起来像是脱离实际的示例,但是有些场景特别有用。例如在浅色屏幕上的深色 Toolbar,或者这个界面(来自 Owl sample app),它大部分是粉色主题,但是底部是一个蓝色主题

A blue sub-section within a pink themed screen

这可以通过在蓝色部分的 root 设置主题,它的子 view 都会受此影响

过度覆盖

由于主题会覆盖其树中 parent 的主题,确保它不会意外地替换您想要保留的属性十分重要。例如,您可能想要改变 view 的背景色(通常由 colorSurface 控制)不做其他更改,即您想保留当前主题的剩余部分。对于这种场景,我们可以使用一种叫做 theme overlays 的技术

这些主题的作用是与其他主题合并。它们的范围可能很狭窄,即它们仅定义(或继承)尽可能少的属性。theme overlays 经常(并非总是)没有 parent

<!-- Copyright 2019 Google LLC.	
   SPDX-License-Identifier: Apache-2.0 -->
<style name="ThemeOverlay.MyApp.DarkSurface" parent="">
  <item name="colorSurface">#121212</item>
</style>
复制代码

theme overlays 的作用范围十分小,它十分克制地定义了尽可能少的属性,目的是为了与其它主题合并共同作用

按照惯例,我们以 ThemeOverlay 作为命名前缀。MDC 和 AppCompat 提供了很多方便的 theme overlays,您可以使用它们为程序的特定部分的颜色做从浅色到深色的转换

  • ThemeOverlay.MaterialComponents.Dark
  • ThemeOverlay.MaterialComponents.Light

根据定义,theme overlays 不会指定很多内容,因此它不应被单独使用。例如,将其用作 activity 的主题。事实上,您可以在 app 中使用两种类型的主题:

  1. “Full” themes,它指定了屏幕所需要的一切,并继承自另一个 full theme,例如 Theme.MaterialComponents。它们应该在 activity 中使用
  2. Theme overlays,与 full theme 配合使用。它不应该独立使用,因为可能会缺失一些必要的内容

注意

总会有一个生效的主题,即使您未在应用中的任何地方指定一个主题,也会继承默认主题。 因此,上面的示例只是一种简化,因此您绝对不应在 View 中使用 full theme,而是应该使用 theme overlays

内存开销

使用主题会在运行期产生一定的开销。每当您声明一个 android:theme,您都在创建一个新的 ContextThemeWrapper 来分配新的 ThemeResource 实例。它还间接引入了更多层的 styling。请谨慎使用主题,尤其在 RecyclerView 这种重复使用的场景下

在 Context 中使用

我们在前文提到主题与 Context 关联——这意味着如果您正在使用 context 来检索代码中的资源,那么请注意使用正确的 context 。例如您在某个位置获取 Drawable

使用错误的 Context

如果 drawable 引用了主题属性(所有的 Drawable 可以在 API 21+ 使用,VectorDrawable 可以通过 Jetpack 在 API 14+ 中使用),则应确保 Drawable 使用了正确的 context。如果您用错了,则可能发现在子节点设置的主题在 Drawable 中不符合预期。例如如果您使用了 Fragment 或者 Activity 的 Context 加载 Drawable,它不会使用当前树的子节点的主题,而是使用最接近传入 Context 的资源

误用

我们已经讨论的「树」中的主题和上下文:Activity > ViewGroup > View。我们很自然的会将这个模式套用在 Application 类中,毕竟您可以在 <application> 标签中指定主题。但别被忽悠了!

Application Context 不包含任何主题信息,您在 manifest 文件中的 <application> 标签设置主题仅作用于那些没指定主题的 Activity。因此不要使用 Application Context 加载那些因主题而异的 资源(drawable 或 color)或者解析主题属性

切勿使用 Application Context 来加载可以的资源

这也是为什么我们为 Activity 指定 full theme,而不会覆盖在 <application> 标签设置的主题

总结

本文解释了 themes overlay 的原理和使用。在你的布局中使用 android:theme 标签配置主题,并使用 theme overlays 来调整您需要的属性。请注意使用正确的主题和 context 来加载资源并小心 application context!

感谢 Florina Muntenescu 和 Chris Banes

译文完

本系列完

系列译文

  • 【译】Android Styling 1: Themes vs Styles

  • 【译】Android Styling 2: 常用主题属性

  • 【译】Android Styling 3: 使用主题和主题属性的优势

  • 【译】Android Styling 4: 主题实战

关于我

我是 Flywith24

  • 掘金

  • 简书

  • Github

这篇关于【译】Android Styling 4: 主题实战的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!