关于项目的各种主题样式是很常见的一个功能,尤其是在一些音乐类型的app中更常见,之前在看Android10的时候有说过新特性中加入了 “暗黑模式”,正好有机会一起讲一下 (最近忙的很,也乱的很,只能半夜充充电了)

若以后有换皮肤的需求,待我用三方架子换个花老虎,睡了,睡了 ~

  • 简单分析
  • 深色主题
    • 基础认知
    • 使用须知
    • 基本使用
    • 工具实现

简单分析

如果让你实现一个日间模式、夜间模式,你会如何去实现?

嗯…我记得好多年前我是有以下想法的

  • 有多少不同主题、模式,我就写多少不同的布局,简而言之就是有多少种模式,我就写多少套布局(好吧,可能很多年前 android 有这么操作的,但是如果现在还这么操作的话,效率就太低了,变成退化阶段了 - 完全不推荐
  • 监听主题变更的事件,在base类封装变装方法,然后子类各自进行设置(嗯… 比一开始的想法好一点,但是几个界面还行,如果项目设计界面较多,且教复杂的话,你基本每个Activity或者View设置类都需要适配,那么也产生了大量的垃圾代码 - 不推荐
  • 通过Theme动态适配不同模式下UI的显示状态

那么我们首先分析一下切换模式时候涉及到哪些方面?

  • 整体的布局颜色肯定需要改变,不说变为黑色,至少是偏向暗色调的,所以意味着关于不同场景的切换,我们要准备俩套color
  • 其次针对于部分需求是需要改变不同模式下的图片,所以我们最好也准备俩天图片

深色主题

Android10 新增的特性 - 深色主题,类似app换皮肤

基础认知

深色主题的特性,具备以下优势

  • 可大幅减少耗电量(具体取决于设备的屏幕技术)- 针对这点,我个人感觉暗色调本身就具备减少电量消耗的功能
  • 为弱视以及对强光敏感的用户提高可视性 - 大白话,没什么意思
  • 让所有人都可以在光线较暗的环境中更轻松地使用设备 - 大白话,没什么意思

在 Android 10 (API 级别 29) 及更高版本中,可通过以下三种方法启用深色主题背景

注意:国内和国外市场不同,国内拥有众多厂商,未必支持以下设置

  • 使用系统设置(Settings -> Display -> Theme)启用深色主题背景。
  • 使用“快捷设置”图块,从通知托盘中切换主题背景(启用后)。
  • 在 Pixel 设备上,选择“省电模式”将同时启用深色主题背景。其他原始设备制造商 (OEM) 不一定支持这种行为

更改应用内主题背景

针对AndroidQ前后版本,默认主题背景稍有不同

当应用在搭载 Android 9 或更低版本的设备上运行时,推荐的主题背景选项是:

  • 浅色
  • 深色
  • 由省电模式设置(推荐的默认选项)

应用在 Android 10 (API 级别 29) 及更高版本上运行时,推荐的选项有所不同,目的是允许用户替换系统默认设置:

  • 浅色
  • 深色
  • 系统默认(推荐的默认选项)

请注意,如果用户选择“Light”,省电模式不会更改该设置。

每个选项直接映射到以下某个 AppCompat.DayNight 模式:

  • 浅色 - MODE_NIGHT_NO
  • 深色 - MODE_NIGHT_YES
  • 由省电模式设置 - MODE_NIGHT_AUTO_BATTERY
  • 系统默认 - MODE_NIGHT_FOLLOW_SYSTEM
使用须知

关于我demo中各sdk版本

android {compileSdkVersion 30buildToolsVersion "30.0.3"defaultConfig {applicationId "com.example.stylemode"minSdkVersion 16targetSdkVersion 30versionCode 1versionName "1.0"testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'}}compileOptions {sourceCompatibility JavaVersion.VERSION_1_8targetCompatibility JavaVersion.VERSION_1_8}
}

因为已经高于Android10版本了,所以关于暗色主题需要的themes资源已自行生成(关于颜色方面,可共用一个colors,自行区分好不同主题的颜色就好)

themes

<resources xmlns:tools="http://schemas.android.com/tools"><!-- Base application theme. --><style name="Theme.StyleMode" parent="Theme.MaterialComponents.DayNight.DarkActionBar"><!-- Primary brand color. --><item name="colorPrimary">@color/purple_500</item><item name="colorPrimaryVariant">@color/purple_700</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><!-- Customize your theme here. --></style>
</resources>

themes(night)

<resources xmlns:tools="http://schemas.android.com/tools"><!-- Base application theme. --><style name="Theme.StyleMode" parent="Theme.MaterialComponents.DayNight.DarkActionBar"><!-- Primary brand color. --><item name="colorPrimary">@color/purple_200</item><item name="colorPrimaryVariant">@color/purple_700</item><item name="colorOnPrimary">@color/black</item><!-- Secondary brand color. --><item name="colorSecondary">@color/teal_200</item><item name="colorSecondaryVariant">@color/teal_200</item><item name="colorOnSecondary">@color/black</item><!-- Status bar color. --><item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item><!-- Customize your theme here. --></style>
</resources>

注意:资源适配

  • 颜色资源:新建values-night文件夹,将页面中使用的色值都替换成暗黑模式下的色值。

  • 图片资源:新建mipmap-night/drawable-night文件夹,将页面中使用的图片和样式资源都替换成暗黑模式下的对应资源。

  • 状态栏:通过上方代码中最后一个方法isDarkMode判断显示什么颜色的状态栏。最好在BaseActivity中操作,否则Activity很多的话很麻烦。

注意:调用适配

场景不同,使用稍有不同,主要是因为主题切换后,activity需要调用recreate方法

  • androidx

可直接调用,因为setDefaultNightMode主动调用了apply方法,使Activity重建

  • support

仅做了赋值操作,未重建activitiy,所以需要自己调用activity.recreate()方法

基本使用

官方文档已经说明了调用方法

 AppCompatDelegate.setDefaultNightMode()

因为setDefaultNightMode需要传入mode(状态),所以我们看看setDefaultNightMode的方法实现(友情提示:关于这个枚举类的具体含义,再上面几行已经说明了,找不到的话自己 Ctrl + F …)

有兴趣可以自己看看 AppCompatDelegate 的方法,还是挺多的…

官方也提供了检查当前主题的方式,看看就好

int currentNightMode = configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK;
switch (currentNightMode) {case Configuration.UI_MODE_NIGHT_NO:// Night mode is not active, we're using the light themebreak;case Configuration.UI_MODE_NIGHT_YES:// Night mode is active, we're using dark themebreak;
}

androidx 使用方式

package com.example.stylemode;import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;import android.os.Bundle;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//日间模式、夜间模式相互切换findViewById(R.id.cut).setOnClickListener(v -> {if (AppCompatDelegate.getDefaultNightMode()<=1){AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);}else{AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);}});}
}

support 使用方式

自己懒得写了,直接引荐下别人滴…

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void click(View v){int mode = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;if (mode == Configuration.UI_MODE_NIGHT_YES) {AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);} else {AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);}getWindow().setWindowAnimations(R.style.WindowAnimationFadeInOut);//不同点recreate();}
}
工具实现

网上有好多这个工具类,我是借鉴于 这里 的

DarkModeUtils

大致一瞥,每次模式切换后将模式的枚举值存入sp,判断模式的时候稍微方便一点点... 这个自己也可以根据枚举值做判断,开心就好

package com.example.stylemode;import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;import androidx.appcompat.app.AppCompatDelegate;public class DarkModeUtils {public static final String KEY_CURRENT_MODEL = "night_mode_state_sp";private static int getNightModel(Context context) {SharedPreferences sp = context.getSharedPreferences(KEY_CURRENT_MODEL, Context.MODE_PRIVATE);return sp.getInt(KEY_CURRENT_MODEL, AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);}public static void setNightModel(Context context, int nightMode) {SharedPreferences sp = context.getSharedPreferences(KEY_CURRENT_MODEL, Context.MODE_PRIVATE);sp.edit().putInt(KEY_CURRENT_MODEL, nightMode).apply();}/*** ths method should be called in Application onCreate method** @param application application*/public static void init(Application application) {int nightMode = getNightModel(application);AppCompatDelegate.setDefaultNightMode(nightMode);}/*** 应用夜间模式*/public static void applyNightMode(Context context) {AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);setNightModel(context, AppCompatDelegate.MODE_NIGHT_YES);}/*** 应用日间模式*/public static void applyDayMode(Context context) {AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);setNightModel(context, AppCompatDelegate.MODE_NIGHT_NO);}/*** 跟随系统主题时需要动态切换*/public static void applySystemMode(Context context) {AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);setNightModel(context, AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);}/*** 判断App当前是否处于暗黑模式状态** @param context 上下文* @return 返回*/public static boolean isDarkMode(Context context) {int nightMode = getNightModel(context);if (nightMode == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) {int applicationUiMode = context.getResources().getConfiguration().uiMode;int systemMode = applicationUiMode & Configuration.UI_MODE_NIGHT_MASK;return systemMode == Configuration.UI_MODE_NIGHT_YES;} else {return nightMode == AppCompatDelegate.MODE_NIGHT_YES;}}}

使用方式

package com.example.stylemode;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);findViewById(R.id.cut).setOnClickListener(v -> {//简单示例哈,有需求看工具类就好了DarkModeUtils.applyNightMode(MainActivity.this);});}
}

Android10.0 特性 - 暗黑模式、深色主题相关推荐

  1. DBeaver EE 21.1.0 安装及深色主题(Dark Theme)配置

    目录 1.DBeaverEE 优势 2.安装DBeaverEE 版本 2.1.安装解压版本JDK11 2.2.配置环境变量 2.2.安装DBeaverEE V21.1版本及PJ 3.安装Dark Th ...

  2. 优酷暗黑模式(四):设计标准化的技术实现

    本文讨论的是如何将 UED 的设计标准化体系在研发侧进行落地,以及我们对"超级 App 实现暗黑模式的最佳实践"这一问题的深度思考. 我们的目的是对 Android 和 iOS 的 ...

  3. 关于Android10 暗黑模式的简述

    前言 Android 10系统增加了暗黑模式,但是并没有像IOS那样强制适配.暗黑模式下可大幅减少耗电量.而且在晚上使用手机的情况下可以有效的保护视力,减少对眼睛的伤害.这个可以在手机的"设 ...

  4. ios12完美深色模式插件_看了微信的暗黑模式后,我也适配了一波安卓!

    作者:Zhujiang, 本文经作者授权发布,链接:https://juejin.im/post/5e95633951882573c2192501 前言 第一次听到暗黑模式的时候,感觉好酷啊,听着就好 ...

  5. css3暗黑主题,利用CSS3自定义属性来为网站添加“暗黑模式”(暗色模式/DarkMode)...

    究竟什么是暗黑模式?这个概念起初来源于macOS系统,该系统的mojave版本为用户提供两个主题皮肤,即浅色和深色的皮肤.自从有了这个概念之后,很多网站和系统都会用户提供了相应的两套肤色,便于用户根据 ...

  6. vue + element-UI 实现深色模式和主题色动态切换

    vue + element-UI 实现深色模式和主题色动态切换 文章目录 vue + element-UI 实现深色模式和主题色动态切换 前言 深色模式和主题色动态切换 本地样式切换 主题色切换 el ...

  7. 安卓暗黑模式软件_安卓微信暗黑模式(深色模式)怎么开启?手机什么条件才支持?...

    最近关于暗黑模式,我们看到了很多人都在找,也都在说怎么找到呀?如何才能找到呢?成了很多人的话题之一,接下来我们就针对这个问题来和大家讨论一下,让大家都知道什么条件才可以支持,从而能够告诉别人,在别人的 ...

  8. 安卓11客制需求:在设定时间开启深色主题模式,21点开启,次日8点关闭

    控制深色模式开启方式的代码在这个路径下面:frameworks/base/core/res/res/values/config.xml 这里可以看到注释里有三个值可以选,系统默认选择的是1,也就是不开 ...

  9. 微信小程序 - 暗黑模式(深色模式)

    最近暗黑模式成为了潮流,微信小程序也推出了暗黑模式适配,下面来记录一个下适配暗黑模式. 效果图:    一.实现 1.开启暗黑模式 在 app.json 中配置 "darkmode" ...

最新文章

  1. Factorization Machine
  2. c 清除 html标签,13.4. 去除HTML的标签tag:htmlRemoveTag
  3. 数据结构 图的定义
  4. android 英文帮助文档地址,使用android SDk帮助文档(英文) 下载中文SDK帮助文档(中文)...
  5. 性能测试工具MultiMechanize的使用介绍
  6. C#如何获得系统时间
  7. 从零开始实现ASP.NET Core MVC的插件式开发(二) - 如何创建项目模板
  8. 解决int和Integer不能互转
  9. 20145226夏艺华 JAVA预备作业1
  10. ZOJ1222 Just the Facts【大数+模除】
  11. 跟燕十八学习PHP-第二十五天-mysqlgroup by和having的综合练习
  12. android使用zxing生成二维码及带logo的二维码
  13. 从零开始的LC刷题(56): Power of Two
  14. 我的政治理想《爱因斯坦文集》
  15. 惠普m154a状态页_惠普m154a感叹号闪烁
  16. 基于C#实现的《勇士返乡》游戏设计
  17. easyswoole入门
  18. html单元格上下拆分代码,在HTML / CSS中如何垂直拆分表格单元格(特殊版本)
  19. 将中文汉字转换成拼音(全拼)
  20. 原谅我不是一个阳光的男孩

热门文章

  1. OpenHarmony/HarmonyOS文本通用属性
  2. 干货 | 为了让携程上万员工上好网,他们做了这些
  3. 有关prototype的理解
  4. 实例化的对象没有prototype属性
  5. DRF访问控制(RBAC)、JWT认证
  6. Scale OUT 与 Scale UP?
  7. js实现:点击为盒子添加样式。边框和整体样式。
  8. 盘点网站百度快照回档或不更新的12种原因
  9. 2020辅警考试计算机知识题,2019辅警考试公共基础知识:计算机知识习题
  10. 深度linux怎么还原系统,如何用深度一键还原系统