假设我有一个包含 2 个主题的应用程序:男性和女性。主题只是改变了调色板和一些可绘制对象来吸引用户的偏好。
我们假装你在做别的事情怎么样?这是一种反设计模式,根据性别关联特定颜色(例如,“女孩喜欢粉红色”)。
这并不是说你的技术目标不好,只是说这是一个非常典型的例子。
例如,我可能想添加一个海盗主题,然后“提交”将是“Arrrrgh!”
仅当“取消”映射到“Avast!”时。
如何通过用户可选择的主题更改整个应用中的字符串?
你还没有说这些字符串是从哪里来的。它们是字符串资源吗?数据库条目?您正在从 Web 服务中检索的那些?还有什么?
我暂时假设这些是字符串资源。根据定义,您需要拥有 N 个字符串副本,每个主题一个。
由于 Android 不会将性别和盗版状态作为可能的资源集限定符进行跟踪,因此您不能让这些字符串资源位于不同的资源集中。虽然它们可能位于不同的文件中(例如,res/values/strings_theme1.xml),但文件名不是字符串资源标识符的一部分。因此,您最终将不得不使用某种前缀/后缀来跟踪哪些字符串属于哪些主题(例如,@string/btn_submit_theme1)。
如果这些字符串在运行时没有改变——它只是你的布局资源中的任何东西——你可以从Chris Jenkins' Calligraphy library获取一个页面。他有自己的LayoutInflater 子类,用于重载一些标准XML 属性。在他的例子中,他的重点是android:fontFamily,他支持映射到资产中的字体文件。
在您的情况下,您可以重载 android:text。在您的布局文件中,而不是指向您的任何实际字符串,您可以让它成为您所需字符串资源的基本名称,没有任何主题标识符(例如,如果真正的字符串是 @string/btn_submit_theme1 和 kin,您可以有android:text="btn_submit")。您的 LayoutInflater 子类将获取该值,附加主题名称后缀,在您的 Resources 上使用 getIdentifier() 来查找实际的字符串资源 ID,然后从那里获取与您的主题相关联的字符串。
对此的一种变体是将基本名称放在android:tag 中,而不是android:text。 android:text 可能指向您真正的字符串资源之一,以帮助进行 GUI 设计等。您的 LayoutInflater 会抓取标签并在运行时使用它来派生正确的字符串。
如果您要用从基于主题的字符串资源中提取的其他文本替换文本,您可以将 get-the-string-given-the-base-name 逻辑隔离到您可以应用的某个静态实用程序方法中。
虽然最初要做到这一点需要一些工作,但它会扩展到任意复杂性,就受影响的 UI 小部件和字符串的数量而言。您仍然必须记住为您定义的任何新字符串添加所有主题的值(用于创建自定义 Lint 检查或 Gradle 任务以验证这一点的奖励积分)。