关于Android样式,系统提供了一种强大的方式来指定应用程序的视觉设计,但很容易被误用。正确使用它可以使主题和样式更容易维护,使更新不那么烦琐,并使其直接支持Dark模式。然而,在使用样式的时候,Theme与Style的概念我们还是要区分清楚。

Theme不等于Style

Theme和Style使用相同的

Style是视图属性的集合,特定于单一类型的小部件。

android style使用 安卓 style_语义属性

如图所示,Style中的每个键都是可以在布局中设置的:

android style使用 安卓 style_应用程序_02

将它们提取为一种样式可以方便地跨多个视图重用和维护。

使用Style由布局中的各个视图使用:

android style使用 安卓 style_语义属性_03

视图只能应用一个样式-与其他样式系统(如web上的css)相比,组件可以设置多个css类。

范围应用于视图的Style仅应用于该视图,而不应用于其任何子视图。例如,如果有一个带有三个按钮的ViewGroup,则在ViewGroup上设置InlineAction样式不会将该样式应用于按钮,Style提供的值与直接在布局中设置的值组合(使用样式优先顺序解析)。

什么是Theme?

Theme是命名资源的集合,这些资源稍后可以被样式、布局等引用。它们为Android资源提供语义名称,以便以后可以引用它们,例如colorPrimary是给定颜色的语义名称:

android style使用 安卓 style_应用程序_04

这些命名资源称为主题属性,因此主题是Map。主题属性不同于视图属性,因为它们不是特定于单个视图类型的属性,而是语义上命名的指向应用程序中更广泛适用的值的指针。主题为这些命名资源提供了具体的值。

在上面的示例中,color primary属性指定此主题的主颜色为teal。通过使用主题抽象资源,我们可以在不同的主题中提供不同的具体值(例如colorPrimary=orange)。

Theme是命名资源的集合,在应用程序中非常有用。

Theme类似于接口,接口编程允许您将公共契约与实现分离,从而允许您提供不同的实现。

Theme扮演着相似的角色,通过根据Theme属性编写布局和样式,我们可以在不同的主题下使用它们,提供不同的具体资源。

大致相当的伪代码:

android style使用 安卓 style_android开发theme_05

它允许我们改变MyView的呈现方式,而不必创建它的变体:

android style使用 安卓 style_css_06

使用我们可以在具有(或是)上下文的组件上指定主题,例如活动或视图/视图组:

android style使用 安卓 style_语义属性_07

还可以通过用CurrestMeTeWrPress包装现有的上下文来设置代码中的主题,然后可以使用该上下文来扩展布局等。

Theme的优点来自于如何使用它们,可以通过引用Theme属性来构建更灵活的小部件,不同的Theme在以后提供了具体的价值。例如,可能希望在视图层次结构的某个部分上设置背景色。

android style使用 安卓 style_语义属性_08

与其设置静态颜色(#ffffff或@color resource),不如使用“?attr/themeAttributeName”语法。

此语法表示:查询主题以获取此语义属性的值。这种间接层次允许我们提供不同的行为(例如,在明暗主题中提供不同的背景色),而无需创建多个布局或样式,这些布局或样式基本相同,但颜色变化很少。它隔离了主题中正在变化的元素。

使用“?attr/themeAttributeName”语法查询主题以获取此语义属性的值

范围Theme是作为上下文的属性访问的,可以从任何具有上下文的对象(如活动、视图或视图组)获取。这些对象存在于树中,其中活动包含包含视图的视图组等。指定树的任何级别上的主题级联到后代节点,例如在View组上设置主题适用于它内的所有视图(与仅适用于单个视图的样式相反)。

android style使用 安卓 style_android style使用_09

这是非常有用的,比如说,如果你想要一个Dark主题的部分,否则轻屏幕。

虽然Context提供了setTheme方法,或者Theme提供了applyStyle方法,但这些都需要在inflate之前调用,设置新主题或应用inflate后的风格不会更新现有视图。

区别对待

了解不同的职责以及Style和Theme之间的交互,有助于使样式资源更易于管理。

例如,假设你的应用程序有一个蓝色的主题,但是一些专业的屏幕有一个漂亮的紫色外观,你想为深色主题提供经过调整的颜色。如果只使用样式来实现此目的,则必须为Pro/non-Pro和light/dark的排列创建4个样式。由于样式特定于视图类型(按钮、开关等),因此您需要为应用程序中的每个视图类型创建这些排列。

android style使用 安卓 style_应用程序_10

如果我们使用样式和主题,我们可以将按主题更改的部分隔离为主题属性,因此我们只需要为每个视图类型定义一个样式。对于上面的示例,我们可以定义4个主题,每个主题都为colorPrimary主题属性提供不同的值,然后这些样式引用并自动反映主题的正确值。

这种方法可能看起来更复杂,因为您需要考虑样式和主题的交互,但它有一个好处,即隔离每个主题更改的部分。

因此,如果你的应用程序从蓝色改名为橙色,你只需要在一个地方更改,而不是分散在你的风格,它也有助于对抗风格的扩散。

理想情况下,每个视图类型只有少量样式。如果不利用主题化的优势,styles.xml文件很容易失控,并爆发出类似样式的不同变体,这将使用我们的维护工作更加复杂。