如何在Android 9.0(Pie)中禁用应用程序的夜间模式,即使夜间模式已启用?

206

在安卓派(Pie)发布之前,我创建了我的应用程序,在每个布局中都放置了 android:background="white"。它在所有设备上都运行良好,但当我的兄弟安装了这个应用程序并启用了夜间模式时,我的应用程序就会像一部黑白电影一样瞬间毁灭。

<style name="AppTheme" parent="Theme.AppCompat.DayNight.DarkActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/COLOR_PRIMARY</item>
    <item name="colorPrimaryDark">@color/COLOR_PRIMARY</item>
    <item name="colorAccent">@color/COLOR_PRIMARY</item>
    <item name="cardViewStyle">@style/CardView</item>
    <item name="android:fontFamily">@font/helvetica</item>
</style>

我的主色调是红色。


您必须为夜间模式调整您的应用程序。Android-Q即将到来,所有应用程序都将受到系统设置的影响。您可以寻找黑暗主题教程。 - ADM
Android 9(Pie)有这样的功能吗?你是不是指的是Android Q? - Leo
@Leo 不是,它是安卓派。 - sai ram
这就是问题所在。Android Pie没有“暗黑主题”。它是在Android Q中引入的。 - Leo
1
有人找到了 Expo 托管应用的解决方法吗?(在此问题得到解决之前 https://github.com/expo/react-native-appearance/issues/60) - ramon_salla
31个回答

205

您可以将此代码放在您的启动活动的 onCreate 方法中的第一行。

AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);

9
我认为另一个解决方案是,您可以拥有一个轻主题,并将其放置在valuesvalues-night中的_style.xml_中。 - Ali Rezaiyan
26
请不要忘记,这个解决方案会导致活动完全销毁和重建。 - Antonis Radz
2
样式文件夹的解决方案是最佳选择。<item name="android:forceDarkAllowed">false</item> - Rohaitas Tanoli
5
<item name="android:forceDarkAllowed">false</item> 所需API级别为29。 - M. H.
2
这对我有用,除了我把它放在我的应用程序文件中而不是我的单个活动和片段中。 - Anna Harrison
显示剩余6条评论

154

在小米Note 8 Pro MIUI 12.0.2 Android 10上进行测试

AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);添加到MainActivity.onCreate();似乎没有起作用

可行的解决方案是在styles.xml中的主要AppTheme块内添加<item name="android:forceDarkAllowed">false</item>

例如:

<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
    <item name="android:forceDarkAllowed" tools:targetApi="q">false</item>
</style>

InputMethodService 更新:

对于 InputMethodService / 如果我们在任何 Service 中膨胀布局
我发现当处于 黑暗模式 - 小米 MIUI 12.0.3 时,一个黑色会变成白色。
为了防止翻转,确保黑色仍然是黑色,请在 InputMethodService 中设置主题。

在调用 super.onCreate() 前,在 onCreate() 方法中调用以下方法:

  • getApplication().setTheme()
  • setTheme()

供您参考,我正在使用 Light Theme (Theme.MaterialComponents.Light.NoActionBar),其中包含 android:forceDarkAllowed=false
在我的情况下,只调用 getApplication().setTheme() 并不能完全防止这种翻转。


这就是我一直在寻找的答案。在我的小米Redmi Note 8手机上,当系统默认为夜间模式时,我的应用程序在选择白天模式时无法正常工作。但是,在我的样式中加入 <item name="android:forceDarkAllowed" tools:targetApi="q">false</item> 后,它可以正常工作了。 - Felix A Marrero Pentón
没有styles.xml文件。 编辑:在themes.xml中添加它可以解决问题。 编辑2:仍然需要setDefaultNightMode才能使其正常工作。 - Benur21
编辑文本存在一个错误,此情况下编辑文本提示不可见。 - Husniddin Muhammad Amin
1
您的解决方案仅适用于我的最低API级别为29的情况。您如何建议为支持较低API级别的应用程序执行此操作? - Yossi
@Yossi 你好,如果我们在android:forceDarkAllowed中添加tools:targetApi="q",就会忽略最低API,像这样:<item name="android:forceDarkAllowed" tools:targetApi="q">false</item> 或者您可以创建styles.xml的API 29版本,并在其中添加android:forceDarkAllowed。 - Fauzi Danartha

117
在 themes.xml 中更改:

<style name="Theme.MyApp" parent="Theme.MaterialComponents.DayNight.DarkActionBar">

<style name="Theme.MyApp" parent="Theme.MaterialComponents.Light.DarkActionBar">

14
这正是我在寻找的。不过,要真正禁用夜间模式,我还删除了“themes.xml(夜间)”。 - Joseph Sang
3
在 themes.xml 中更改为夜间版本。 - Rudra Raina
2
请不要忘记从values-night文件夹中删除theme.xml文件。 - Khaled Saifullah

105

React Native, Ionic (cordova, capacitor)

实际上,这个答案是特别针对React Native开发者/应用的:

就像我们所有人都知道的那样,深色模式在Android 10上完全可用。

深色主题在Android 10(API级别29)及更高版本中可用

很可能这个功能破坏了你的应用设计实现,比如SVG、字体和背景颜色。如果你决定完全禁用force dark mode,你应该遵循这个方法:

  1. Append the following code inside your <style> tag in the styles.xml file:

    <item name="android:forceDarkAllowed">false</item>
    

    Note: file path: android/app/src/main/res/values/styles.xml

  2. After step 1 you shoule have something like below:

    <resources>
      <!-- Base application theme. -->
      <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
          ...
          <item name="android:forceDarkAllowed">false</item>
      </style>
    </resources>
    
  3. Maybe the above steps don't help you but don't worry, just like is said in the top of this post, this feature is released on API level 29, this means you should change the compileSdkVersion to 29 or higher.

  4. To Change the compileSdkVersion you should edit the the compileSdkVersion in the app gradle properites existed in the android/app/build.gradle file:

    android {
        compileSdkVersion 29
    
  5. Maybe you face compileSdkVersion rootProject.ext.compileSdkVersion, don't worry you should change this in the android gradle properites existed in the android/build.gradle file:

    buildscript {
        ext {
            buildToolsVersion = "SomeVersion"
            minSdkVersion = SomeVersion
            compileSdkVersion = 29 // <======= this should be 29 or higher
            targetSdkVersion = SomeVersion
    

提示: 为确保您拥有新的构建,请使用rm -rf android/app/build命令完全删除上一个构建,并在模拟器/设备上卸载应用程序,然后再次运行yarn android


1
这个答案属于我,如果有问题,请@我。谢谢。 - AmerllicA
1
@AmerllicA,我尝试了你的解决方案和在onCreate中的方法,但都没有起作用。我进行了新的构建并在我的小米Mi 10T Lite上尝试了它。 - Aldimir
@AldimirAleknsandrov,很奇怪,因为在任何情况下它都应该工作,实际上,使用这个解决方案,您完全关闭了暗黑主题,请将29替换为30,也许它会起作用,请告诉我效果。 - AmerllicA
@AmerllicA 我的默认值实际上是29,最小值为21。 - Aldimir
有没有适用于Expo的解决方案? - Mitch
显示剩余4条评论

36
如果您想要避免Activity的重新创建,可以按照这里所述,在Application类上设置标志位。

我建议像这样在您的应用程序类中设置:

public class MyApplication extends Application {
    
    public void onCreate() {
        super.onCreate();
        AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
    }
}

25

如果您想在应用程序的所有部分中禁用夜间模式,Ali Rezaiyan建议采取正确的方法。

有时您只需要在某些活动或片段上禁用夜间模式(可能是由于旧版问题)。

因此,您可以选择要执行的操作:

  • 全局禁用:

    • AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
  • 仅禁用单个活动:

    • getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_NO);
    • 调用此方法后,您可能需要调用recreate()才能生效

1
我曾遇到一个问题,即在活动中使用 AppCompatDelegate.setDefaultNightMode() 导致在活动启动时调用了 onNewIntent 方法。 但是 getDelegate().setLocalNightMode() 成功解决了我的问题。感谢它的帮助。 - Reza Abedi

23

这对我有用(2021年4月)

  1. 在您的主题下添加以下行:

<item name="android:forceDarkAllowed" tools:targetApi="q"> false </item>

  1. 删除themes.xml(位于values文件夹下的night文件)

在资源标签中,与xmlns:tools="http://schemas.android.com/tools"一起添加了这行代码到styles.xml文件中。但是对我来说没有起作用。我应该把它添加到其他地方吗? - Suraj Ingle
你应该将它添加到你的 'themes.xml' 文件中。 可以在此路径下找到:res > values > themes.xml - Ehsan Rosdi
我正在使用React Native,显然它没有themes.xml文件,而是有styles.xml文件,其中包含以下标签:<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">。因此,我认为这一定是主题。 - Suraj Ingle
但是在主题更改时仍然会重新启动活动。如何防止这种情况发生? - Samudra Ganguly

20

<style name="Theme.MyApp" parent="Theme.MaterialComponents.DayNight.DarkActionBar">

将两个主题 DayNight 变为 Light

<style name="Theme.MyApp" parent="Theme.MaterialComponents.Light.DarkActionBar">


14

这对我起了作用,我将以下代码

<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">

替换为以下代码:

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">

文件路径: android/app/src/main/res/values/styles.xml

所有代码:

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="android:textColor">#000000</item>
</style>

9

请勿使用以下代码。

AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);

这将调用您的活动两次。
只需简单地使用以下方法:
在您的主题文件中,
首先将样式父级设为Light。
Theme.MaterialComponents.Light.NoActionBar

请在您的样式下添加以下行:
<item name="android:forceDarkAllowed" tools:targetApi="q">false</item>

那么你的代码应该长这样。

<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
        <!-- Primary brand color. -->
        <item name="colorPrimary">@color/primary_color_app</item>
        <item name="colorPrimaryVariant">@color/status_bar_color</item>
        <item name="colorOnPrimary">@color/white</item>
        <!-- Secondary brand color. -->
        <item name="colorSecondary">@color/teal_200</item>
        <item name="colorSecondaryVariant">@color/teal_700</item>
        <item name="colorOnSecondary">@color/black</item>
        <!-- Status bar color. -->
        <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>

        <item name="android:forceDarkAllowed" tools:targetApi="q">false</item>

        <!-- Customize your theme here. -->
    </style>

注意:如果您使用更新的Android Studio版本,请确保您需要使夜间主题的样式相同。 与浅色主题相同的颜色


根据Android文档,“如果在已创建任何附加了AppCompatDelegates的主机组件之后调用此方法,则每个都会发生uiMode配置更改。” 我将其添加到App类中,没有任何东西被调用两次,并且适用于整个应用程序。 - ravindu1024

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接