简单地使用适用于 Android View 的 Material 3 品牌色

326 阅读2分钟

使用谷歌的 Material Theme Builder(MTB) 可以直接导出适用于 Android View 的资源,但这有一些问题

存在的问题

  1. 生成多套主题:导出后的资源会继承自默认主题,通过在主题中定义 colorPrimary 等各种色调。MD3 中亮色与暗色模式下的颜色是不一样的,所以需要生成多套主题。
  2. 文字选择的背景颜色还是默认的紫色:生成后的主题并未复写 textColorHighlight 等属性,而 textColorHighlight 等属性没有引用到 colorPrimary,而是引用到了 @color/m3_sys_color_light_primary@color/m3_sys_color_dark_primary,这两个颜色依旧是紫色,因此不生效。

新的方法

通常,一个简单的 APP 不需要提供主题颜色切换功能,使用继承主题并复写主题属性的方法会很麻烦,而且会多出很多无关代码。因为 MD3 的颜色最终会引用到默认的 palettes,所以复写这些 palettes 就可以达到使用品牌色的目的,并且不需要生成额外的样式和代码。

token 是可以从 MTB 中生成,但是生成后的 palettes 中缺少了很多颜色,比如 m3_ref_palette_neutral4m3_ref_palette_neutral6 因此还需要从 schemes 提取相应的颜色。

  1. 首先获取 token:在 Material Theme Builder 生成 json 文件,放到与 MD Ref 生成器相同的目录
  2. 双击 MD Ref 生成器
  3. 将生成的 colors_refs.xml 文件复制到 values 文件夹中。这个文件的名称可以随便写,我觉得colors_palettes.xml 或者 colors_tokens.xml 更好一些。

MD Ref 生成器源代码

这是我使用python3编写的工具,在这篇文章之前我仅在 GitHub 中传播。

"""
MIT License
"""

import json

with open("./material-theme.json") as f:
    content = json.load(f)
generated = ""
for name, palettes in content["palettes"].items():
    for level, color in palettes.items():
        generated += f"""\n    <color name="m3_ref_palette_{name.replace("-", "_")}{level}">{color}</color>"""

with open('colors_refs.xml', 'w') as f:
    f.write(f"""<?xml version="1.0" encoding="utf-8"?>
<!-- This file was generated from the material-theme.json that was created on
    https://material-foundation.github.io/material-theme-builder/. -->

<!-- Only rewriting the colors in the theme is not enough. 
    Because some resources directly reference resource colors instead of attr. 
    So we rewrite these resource colors here. -->
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:ignore="PrivateResource">
{generated}

    <!-- Here are the palettes that are not in material-theme.json -->
    <!-- Retrieved from colorOnSurfaceXxx
        according to https://m3.material.io/styles/color/static/baseline -->
    <!-- Dark Surface Container Lowest -->
    <color name="m3_ref_palette_neutral4">{content["schemes"]["dark"]["surfaceContainerLowest"]}</color>
    <!-- Dark Surface -->
    <color name="m3_ref_palette_neutral6">{content["schemes"]["dark"]["surface"]}</color>
    <!-- Dark Surface Container -->
    <color name="m3_ref_palette_neutral12">{content["schemes"]["dark"]["surfaceContainer"]}</color>
    <!-- Dark Surface Container High -->
    <color name="m3_ref_palette_neutral17">{content["schemes"]["dark"]["surfaceContainerHigh"]}</color>
    <!-- Dark Surface Container Highest -->
    <color name="m3_ref_palette_neutral22">{content["schemes"]["dark"]["surfaceContainerHighest"]}</color>
    <!-- Dark surface Bright -->
    <color name="m3_ref_palette_neutral24">{content["schemes"]["dark"]["surfaceBright"]}</color>
    <!-- Light surface Dim -->
    <color name="m3_ref_palette_neutral87">{content["schemes"]["light"]["surfaceDim"]}</color>
    <!-- Light Surface Container High -->
    <color name="m3_ref_palette_neutral92">{content["schemes"]["light"]["surfaceContainerHigh"]}</color>
    <!-- Light Surface Container -->
    <color name="m3_ref_palette_neutral94">{content["schemes"]["light"]["surfaceContainer"]}</color>
    <!-- Light Surface Container Low -->
    <color name="m3_ref_palette_neutral96">{content["schemes"]["light"]["surfaceContainerLow"]}</color>
</resources>
""")
print(generated)