使用谷歌的 Material Theme Builder(MTB) 可以直接导出适用于 Android View 的资源,但这有一些问题
存在的问题
- 生成多套主题:导出后的资源会继承自默认主题,通过在主题中定义
colorPrimary等各种色调。MD3 中亮色与暗色模式下的颜色是不一样的,所以需要生成多套主题。 - 文字选择的背景颜色还是默认的紫色:生成后的主题并未复写
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_neutral4、m3_ref_palette_neutral6 因此还需要从 schemes 提取相应的颜色。
- 首先获取 token:在 Material Theme Builder 生成 json 文件,放到与 MD Ref 生成器相同的目录
- 双击 MD Ref 生成器
- 将生成的
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)