如何以编程方式创建Android主题样式?

Mer*_*ury 23 android android-styles

有很多关于通过XML创建或自定义Android主题样式的文档和教程,但是还没有找到在代码中创建它的方法.关于如何在代码而不是xml中创建样式的任何想法?

这是示例XML,需要在代码中以编程方式创建:

<resources>
  <style name="AppTheme" parent="android:Theme.Material">
    <item name="android:colorPrimary">@color/primary</item>
    <item name="android:colorPrimaryDark">@color/primary_dark</item>
    <item name="android:colorAccent">@color/accent</item>
  </style>
</resources>
Run Code Online (Sandbox Code Playgroud)

Dav*_*zzo 7

TL;DR:只是不,你不能。这就是 Android 的工作方式,并且永远不会改变。

\n
\n

有一个简单明了的原因可以解释为什么以编程方式创建 Android 主题永远不可能。也就是说,当应用程序启动时,Android 会创建一个虚拟窗口来显示应用程序的android:windowBackground. 此时,应用程序进程仍在初始化,当应用程序开始执行并且Activity.onCreate正在启动的活动的方法返回时,虚拟窗口将替换为显示该活动的应用程序窗口。
\n因此,事实是,由于android:windowBackground是由主题设置的,但 Android 必须在应用程序启动之前访问它,因此主题必须是资源,以便可以从任何进程(当然包括系统进程)访问它们。

\n

此外,主题是资源,因此它们是完全不可变的。这就是 Android 的工作原理。它不可能突然改变,而且也不太可能永远改变。资源永远无法动态修改的另一个原因是直接暗示 APK 本身也需要修改 \xe2\x80\x94,而这也不是 APK 的含义。

\n

有人可能会说 \xe2\x80\x9c 所有事情都必须在幕后以编程方式完成。 \xe2\x80\x9d 嗯,这是正确的。然而,该类android.content.res.Resources.Theme是最终类是有原因的,即确保没有任何内容被覆盖,从而保证其行为反映资源所说的内容,这对于访问android:windowBackground活动主题的系统进程与活动主题保持一致是基础。应用程序启动后的行为方式。对于android.content.Context.obtainStyledResources方法也是如此,它也是最终的。事实上,如果应用程序可以重写该方法,它将能够返回与资源不匹配的值,这是一个问题,因为只有在应用程序进程启动后(当原始的真实数据已经显示时)才会发生这种情况android:windowBackground。

\n

  • 这个论点通常是有道理的,但它让我想知道为什么存在以下方法: https://developer.android.com/reference/android/content/res/Resources#newTheme() 资源公开了一个 `newTheme()` 方法。 (2认同)

Ren*_*han 6

答案很简单:它不可能通过编程创建主题和设置为应用主题(即使我们实现创建一个Theme对象)没有主题资源ID。

细节:

当你调用setTheme函数无效的一个方法时ContextWrapper,它最后AssetManager用资源id指针调用,AssetManager类持有应用程序主题的方法,即JNI调用

native static final void applyThemeStyle(long theme, int res, boolean force);
Run Code Online (Sandbox Code Playgroud)

如上所述,我们只能传递一个资源 id 来应用主题样式。但可能的选择是

  1. 虽然它仅限于Window类功能常量。我们可以使用 setFeatureDrawable和特征常量来设置一些可绘制对象,例如FEATURE_ACTION_BAR,FEATURE_CONTEXT_MENU等等。
  2. 使用activity中的setTheme函数,我们可以从style资源中设置主题,这样就解决了AjaySharma&的评论中提到的问题Nathan

  • 借助 Jetpack Compose,您可以在运行时动态更改主题属性,所以是的...2020 年没有让我们失望。XML 和 UIKit 已死,Compose 和 SwiftUI 长存 (2认同)