如果看过了 Support Library 23.2.0 博客,你就会知道 AppCompat 现在有个新的主题:Theme.AppCompat.DayNight.
这个主题可以根据系统时间切换 Theme.AppCompat(暗色) 和 Theme.AppCompat.Light(亮色) 两种主题。这将会对应用的用户特别有用,特别是阅读类应用(这已经成为了阅读软件的标配)。需要注意的是,这个特性只支持 API v14 及以上的 Android 设备,在 API v14 以下的设备则会默认使用亮色的主题。
怎样使用 DayNight 主题?
DayNight 主题使用起来很简单,只需要把你的主题继承 DayNight 主题,然后应用。例如:
<!-- parent 为 Theme.AppCompat.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 呢?
让我们假设一下应用场景,帮你更清晰的思考这个问题:
- 更改主题,使它继承自 Theme.AppCompat.DayNight
- 添加用户切换主题的设置项。把用户设置的信息存储到本地(比如 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
我们不保证这种用法适用于全部应用,但是如果你在合适的时机使用,还是会很有帮助的。
查看原文:https://medium.com/@chrisbanes/appcompat-v23-2-daynight-d10f90c83e94#.35278z4j5
译者注:如果你想了解更多 AppCompat v23.2 的新特性,推荐你看一下秋百万的android-support-23.2-sample