Android夜间模式官方最佳实践

昨晚发过这篇,其中我关于“掘金获得谷歌国内最佳Material Design应用提名”的说法有问题,被谷歌的朋友提醒后,决定还是删了重发,非常抱歉之前帮忙转发的朋友,即便如此,也并不影响我对掘金的推荐,确实是非常棒的一款产品,技术干货超多,大家可以多关注 http://gold.xitu.io


今天这篇译文就来自稀土掘金Android工程师 NeXT 同学,NeXT非常热衷分享,掘金上大量的好文章都分享自他。


原文来自Android大神Chris Banes介绍Android夜间模式新特性的文章,我之前给大家也推过关于Android夜间模式最佳实践的文章,以前Android官方对夜间模式的支持不太给力,因此大家也想出了各种方案,今后也许可以都采用这个方案实现吧,当然它也有一些限制,比如仅支持API 14及以上、仍然需要recreate Activity, 不过我个人以为现在新开发Android应用已经无须再顾及API 14以下的用户了,而且recreate Activity其实也没什么大不了,各位不要太纠结(主要是PM不要太纠结)。


如果看过了 Support Library 23.2.0 博客(http://android-developers.blogspot.com/2016/02/android-support-library-232.html),你就会知道 AppCompat 现在有个新的主题:Theme.AppCompat.DayNight.

这个主题可以根据系统时间切换 Theme.AppCompat(暗色) 和 Theme.AppCompat.Light(亮色) 两种主题。这将会对应用的用户特别有用,特别是阅读类应用(这已经成为了阅读软件的标配)。需要注意的是,这个特性只支持 API v14 及以上的 Android 设备,在 API v14 以下的设备则会默认使用亮色的主题。

怎样使用 DayNight 主题?

DayNight 主题使用起来很简单,只需要把你的主题继承 DayNight 主题,然后应用。例如:


<style name="MyTheme" parent="Theme.AppCompat.DayNight">
   -- Blah blah -->
style>

然后在程序中进行主题的初始化。你需要调用 AppCompatDelegate.setDefaultNightMode() ,它有四个参数:

  • MODE_NIGHT_NO. 使用亮色(light)主题

  • MODE_NIGHT_YES. 使用暗色(dark)主题

  • MODE_NIGHT_AUTO. 根据当前时间自动切换 亮色(light)/暗色(dark)主题

  • MODE_NIGHT_FOLLOW_SYSTEM(默认选项). 设置为跟随系统,通常为 MODE_NIGHT_NO

你可以在任何时候调用这个方法,因为这个方法是静态的。你设置的值不是一直存在的,所以你需要在每次程序开启进程时重新设置。我建议你在 application 类或者 Activity 中添加一个静态代码块来进行设置,比如:

static {
    AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_...);
}

public class MyApplication extends Application {

设置程序日夜间模式 setLocalNightMode()

你可以通过调用 AppCompatDelegate 的 setLocalNightMode() 方法来重写每个组件的默认值。如果你知道有一些组件是使用 DayNight 方法的时候,这是很好用的。对与开发者来说,你不用等到太阳下山就可以测试夜间模式了呢。

请注意,这个方法并不会实时更新布局。你需要调用 recreate() 来通知页面更新。使用方式如下:

public class MyActivity extends AppCompatActivity {

   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       if (savedInstanceState == null) {
           //Set the local night mode to some value            getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_...);
           //调用recreate()使设置生效            recreate();        }    } }

怎样获取应用当前的主题?

只需要检测资源配置:

int currentNightMode = getResources().getConfiguration().uiMode
   & Configuration.UI_MODE_NIGHT_MASK;

switch
(currentNightMode) {
   case Configuration.UI_MODE_NIGHT_NO:
       // Night mode is not active, we're in day time    case Configuration.UI_MODE_NIGHT_YES:
       // Night mode is active, we're at night!
   case Configuration.UI_MODE_NIGHT_UNDEFINED:
       // We don't know what mode we're in, assume notnight    
}

文字、图片适配(为什么我的应用看起来很奇怪?)

艾玛,我看不见字了(黑色文字黑色背景)。艾玛,我的图标怎么这么丑。

当这个功能更改了程序主题时,你需要确定你的 布局/样式/图片 都适配了亮色(light)和暗色(dark)主题。

这种资源适配的经验法则就是:尽可能的使用主题属性(theme attributes)。下面是一些需要重点了解的:

  • ?android:attr/textColorPrimary. 系统默认的文字颜色。在亮色(light)主题下,颜色接近黑色,在暗色(dark)主题下,颜色接近白色。Contains a disabled state.

  • ?attr/colorControlNormal. 系统默认的图标颜色

关于 WebView

需要重点注意 WebView. WebView 不能使用主题属性(theme attributes),并且我们很难控制网页内容的样式,所以很有可能你的 WebView 跟程序其他主题颜色不符。所以,请确认你的 WebView 页面的主题尽量跟应用当前主题相同。

坐标!坐标!!坐标!!!

想要精确的自动切换日夜间模式,需要获取系统的位置。这可能会让开发者感到菊花一紧,不过不用害怕,如果你的程序被授予了坐标权限(location permission),AppCompat 会试着获取 LocationManager 中上次保存的坐标,根据坐标计算日出日落时间。并不需要程序请求任何权限。

如果程序没有位置权限(或者 LocationManager 没有存储上次坐标的信息),那么,系统会默认设置为早上6点钟为日出,下午10点钟为日落,如果用户调整系统时间,当前的主题也会随之改变。

为什么不直接设置主题为 AUTO 呢?

让我们假设一下应用场景,帮你更清晰的思考这个问题:

  1. 更改主题,使它继承自 Theme.AppCompat.DayNight

  2. 添加用户切换主题的设置项。把用户设置的信息存储到本地(比如 SharedPreference)。根据用户选择的参数调用 setDefaultNightMode() 方法。

下次启动程序的时候,读取本地文件然后根据用户设置,调用 setDefaultNightMode() 方法。

重点来了:我们不希望用户在设定主题后,主题还会根据当前的时间突然改变。请记得,默认的主题是 MODE_NIGHT_FOLLOW_SYSTEM, 如果我们添加一个用户可以设置主题的功能,AppCompat 会默认使用

切换主题时使用自定义资源

使用自定义资源,只需要在 res 目录下创建对应的 values-night 文件夹并创建对应的 themes.xml 文件:
res/values/themes.xml

<style name="Theme.AppCompat.DayNight" 
       parent="Theme.AppCompat.Light" />

res/values-night/themes.xml

<style name="Theme.AppCompat.DayNight" 
       parent="Theme.AppCompat" />

只要在对应的资源文件夹后添加 -night 后缀,比如:drawable-night、values-night, 等等…

Night night

我们不保证这种用法适用于全部应用,但是如果你在合适的时机使用,还是会很有帮助的。

译者注:如果你想了解更多 AppCompat v23.2 的新特性,推荐你看一下秋百万的android-support-23.2-sample

https://github.com/liaohuqiu/android-support-23.2-sample

你可能感兴趣的:(个人文章)