在Android上是否可以使用夜间预选赛来启动屏幕?

时间:2019-06-29 19:10:57

标签: android android-night-mode

背景

我知道Android Q上有一项新功能,可以最终支持深色主题(关于检测该主题的问题,写成here)。

我还知道,有“夜灯”功能(here)使屏幕变黄。

多年来,我已经完成了手动支持主题选择的工作(仅在Activity的onCreate的第一行代码中使用setTheme),但是我想知道是否有自动的东西可以让我进行设置甚至在应用真正启动之前,就在启动屏幕中。

问题

似乎很老的功能(自API 8开始)在Android上已经存在很长时间了,它在资源中使用了“夜间”限定符,而我从未尝试过。

不幸的是,由于“黑暗主题”和与夜晚有关的内容现在作为新功能(here for example)越来越多地被谈论,所以我找不到旧的含义。

不过,看一些文章和文档,似乎几乎完全是手动的:

我尝试过的

我试图相应地设置各种主题:

res / drawable / splash.xml

  <layer-list xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:opacity="opaque" tools:ignore="UnusedAttribute">
    <item android:gravity="fill">
      <shape android:shape="rectangle">
        <solid android:color="#fff"/>
      </shape>
    </item>
    ...
  </layer-list>

res / drawable-v29 / splash.xml

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:opacity="opaque" tools:ignore="UnusedAttribute">
  <item android:gravity="fill">
    <shape android:shape="rectangle">
      <solid android:color="?attr/colorSurface"/>
    </shape>
  </item>
  ...
</layer-list>

res / drawable-night / splash.xml

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:opacity="opaque" tools:ignore="UnusedAttribute">
  <item android:gravity="fill">
    <shape android:shape="rectangle">
      <solid android:color="#000"/>
    </shape>
  </item>
  ...
</layer-list>

清单

res / values / themes.xml

  <style name="AppTheme_splash" parent="@style/Theme.MaterialComponents.DayNight">
    <item name="android:windowBackground">@drawable/splash</item>
  </style>

res / values-v26 / themes.xml

  <style name="AppTheme_splash" parent="@style/Theme.MaterialComponents.DayNight">
    <item name="android:windowSplashscreenContent">@drawable/splash</item>
  </style>

我试图删除android:windowBackgroundandroid:windowSplashscreenContent,试图查看它是否是自动的,但并没有帮助。

问题

基本上,我只想了解夜间模式以及是否可以将其用于启动屏幕:

  1. Android如此长时间支持的“夜间模式”何时开始?

  2. 这是OS全局模式吗?用户可以控制吗?

  3. 这是自动的吗?还是完全由当前应用手动完成?

  4. 即使我由应用程序手动设置该模式并且该应用程序被杀死,该模式还会在以后保留吗?

  5. 是否可以设置应用程序的主题(对于启动屏幕而言)以使用此主题,以便在启用夜间模式时,它将使用它具有深色背景?

  6. 我的代码是否正确?

2 个答案:

答案 0 :(得分:0)

1)那些资源限定符不会自动将其踢出去,它们被用于提供系统范围的回调和android auto功能的资源,可以更改该模式,但是它是系统范围的,因此不建议将其用于夜间模式;

2)新的夜间模式是一个全局设置,但是在不同的API级别上其工作原理不同,但是id确实使用了旧的资源限定符“ night”。

3)旧的“夜间”模式是自动的,并且在整个系统范围内运行,它是在设备停靠后和一小时后(例如:6:00 PM)触发的(想想如果汽车导航在此环境黑暗时会切换到黑暗模式)是原本打算的)。如果您的应用程序支持您的活动将获得回调,并且活动将重新启动并使用夜间资源。 “新的”夜间模式使用相同的资源,但是他们添加了新的API来切换资源,而不是回叫,而是询问系统正在使用哪种模式并相应地设置资源(您可以让活动使用不同的模式,因为您明确地说应该使用哪些资源)。简而言之,完全是手动的。

4)如果您要保留设置(例如,如果用户正在使用您的应用并且他希望您的应用为深色),则无论该系统设置是什么,您都必须保存并处理该设置,该选项不会保留在应用启动时。否则,应用程序将以默认模式启动(即使系统设置设置为黑暗,该模式也会亮起)。

5)是的,可能有应用程序级别的夜间模式(您只是告诉系统在Application.onCreate()方法中为应用程序使用“夜间”资源)。

6)您的代码部分正确,您还需要告诉系统使用这些资源。

class MyApp : Application() {
// shared pref setting to save user preference for our app. Add your own implementation of shared pref here, I use dependency injection to get the shared preferences
    private val sharedPreferences: SharedPreferencesWrapper by inject() 

    override fun onCreate() {
        super.onCreate()

    // here we say to the system witch resources our application should use since we handle this in application level this will affect all out activities and the splash screen, but we could set it for individual activities as well
    // i'm using a lambda here to listen to when the user changes the setting inside our app and the framework will handle the activities restart
        preferences.nightMode.onChange(true) {
           when (sharedPreferences.nightMode) {
               AppCompatDelegate.MODE_NIGHT_YES -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)  // our app want to be light so it will use default resouces
               AppCompatDelegate.MODE_NIGHT_NO -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) // our app wants to be dark so it will use the "night" resources
               AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY) // our app wants to be dark if on battery saving (because there was no nigh-mode setting that the user had access to on API < Q) this is recommended by google
               AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) // our app wants to follow the system setting (this is only available in Q+ in API < Q if we use this is does nothing) 
            }
        }
    }
}

现在,您只需将“ night”资源放在“ yourResource” -night文件夹中即可,例如:drawable / drawable-night,values / values-night”,我选择了2种样式,一种亮一种暗

在values / styles.xml

<resources>
    <style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
        <!-- Customise your theme here. -->
        <!--status bar-->
        <item name="android:statusBarColor">@color/light_background</item>
        <!--background-->
        <item name="android:colorBackground">@color/light_background</item>
        <item name="android:windowBackground">@color/light_background</item>
    </style>
</resources>

和values-night / styles.xml

<resources>
    <style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
        <!-- Customise your theme here. -->
        <!--status bar-->
        <item name="android:statusBarColor">@color/dark_background</item>
        <!--background-->
        <item name="android:colorBackground">@color/dark_background</item>
        <item name="android:windowBackground">@color/dark_background</item>
    </style>
</resources>

摘自文档"Note that dark-themed android:windowBackground drawables only work on Android Q."

现在,最后一步是确保我们的活动扩展了Appcompat活动

class MainActivity : AppCompatActivity(){}

我使用以下版本,是因为当主题更改时,活动如何重新启动(之前有一些闪烁)

implementation "androidx.appcompat:appcompat:1.1.0-beta01"

我在API 21+上测试了所有内容,并按预期工作

答案 1 :(得分:0)

实际上,可以为启动屏幕添加一个夜间修改器。

可悲的是,它会在使用任何代码之前立即发生。因此,它完全基于操作系统的设置,而不是基于应用程序本身。

此外,IDE上还有一个令人烦恼的问题,即对于每个活动,它将首先使用我为启动创建的这个主题。

除了上述两个缺点之外,其他方法都可以正常工作,您可以在我的应用here上亲眼看到它。

这里:

res / drawable / splash.xml

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
    android:opacity="opaque" tools:ignore="UnusedAttribute">
    <item android:gravity="fill">
        <shape android:shape="rectangle">
            <solid android:color="#fff" />
        </shape>
    </item>
    <item
        android:width="48dp" android:height="48dp" android:gravity="center">
        <bitmap
            android:gravity="center" android:src="@mipmap/ic_launcher_foreground" />
    </item>
</layer-list>

res / drawable-night / splash.xml

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
    android:opacity="opaque" tools:ignore="UnusedAttribute">
    <item android:gravity="fill">
        <shape android:shape="rectangle">
            <solid android:color="#000" />
        </shape>
    </item>
    <item
        android:width="48dp" android:height="48dp" android:gravity="center">
        <bitmap
            android:gravity="center" android:src="@mipmap/ic_launcher_foreground" />
    </item>
</layer-list>

themes.xml

    <style name="AppTheme_splash" parent="@style/Theme.MaterialComponents.DayNight">
        <item name="android:windowBackground">@drawable/splash</item>
        <item name="android:navigationBarColor" tools:targetApi="lollipop">@android:color/transparent</item>
        <item name="android:statusBarColor" tools:targetApi="lollipop">?android:colorBackground</item>
        <item name="colorSecondary">?colorAccent</item>
        <item name="android:colorSecondary" tools:targetApi="n_mr1">?colorAccent</item>
    </style>

清单

  <application android:theme="@style/AppTheme_splash" ...">