Android 深色模式的项目应用
前言
早在四年前就准备做深色模式的,当时用的三方的SDK,但是SDK上还有bug,不能适配RecyclerView,用上后会很卡,然后就一直放着了,有些用户一直催着要深色模式:
然后这段期间给整上,本以为现在深色模式应用的挺广泛的,在项目中实践了一下还是躺了很多坑,梳理一下实践过程及遇到的问题。
所有代码实践在云阅里可以看到:
- 下载App体验,酷安:云阅
- 直接查看源码,GitHub:CloudReader
项目实践
1.选定原生Api实现
Android官方深色主题背景开发文档(需科学上网)。
原生Api简单稳定但是就是要重启App,不过看掘金以及微信都是这样实现的。
于是参考了微信和掘金的操作,总有三种状态,跟随系统,普通模式,深色模式。
2.关键的工具类
public class NightModeUtil {/*** 当前系统是否是深色模式*/public static boolean isNightMode(Context context) {int uiMode = context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;return uiMode == Configuration.UI_MODE_NIGHT_YES;}/*** 获取是否跟随系统,默认true*/public static boolean getSystemMode() {return SPUtils.getBoolean(Constants.KEY_MODE_SYSTEM, true);}public static void setSystemMode(boolean nightMode) {SPUtils.putBoolean(Constants.KEY_MODE_SYSTEM, nightMode);}/*** 获取是否设置深色模式,默认false*/public static boolean getNightMode() {return SPUtils.getBoolean(Constants.KEY_MODE_NIGHT, false);}public static void setNightMode(boolean nightMode) {SPUtils.putBoolean(Constants.KEY_MODE_NIGHT, nightMode);}public static void initNightMode() {initNightMode(getSystemMode(), getNightMode());}/*** 初始化App深色模式** @param systemMode 是否是跟随系统* @param nightMode 是否是深色模式*/public static void initNightMode(boolean systemMode, boolean nightMode) {if (systemMode) {AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);} else {if (nightMode) {AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);} else {AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);}}}/*** 重启App*/public static void restartApp(Activity activity) {final Intent intent = App.getInstance().getPackageManager().getLaunchIntentForPackage(App.getInstance().getPackageName());if (intent != null) {intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);activity.startActivity(intent);android.os.Process.killProcess(android.os.Process.myPid());}}
}
3.在Application里初始化
NightModeUtil.initNightMode();
4.切换状态后重启App
NightModeUtil.initNightMode(dayNightSwitch.isChecked, ctvCheckNight.isChecked)
NightModeUtil.restartApp(activity)
其中还要保存是否跟随系统或指定深色模式的状态,具体逻辑细节可见:NavNightModeActivity.kt
5.Application下的主题设置
<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar"><!--选中状态icon的颜色和字体颜色--><item name="colorPrimary">@color/colorTheme</item><item name="colorPrimaryDark">@color/colorTheme</item><item name="colorAccent">@color/colorTheme</item><item name="android:windowAnimationStyle">@style/default_animation</item><item name="android:listDivider">@drawable/shape_line</item><!--默认状态下页面的背景色--><item name="android:windowBackground">@color/color_page_bg</item>
</style>
同时还要注意如果单个Activity有自己的主题,也需要设置parent主题为Theme.AppCompat.DayNight.NoActionBar
。
ToolBar也有自己的主题:
<androidx.appcompat.widget.Toolbar xmlns:app="http://schemas.android.com/apk/res-auto"android:id="@+id/tool_bar"android:layout_width="match_parent"android:layout_height="?attr/actionBarSize"android:background="@color/colorToolBar"app:contentInsetStart="0.0dp"app:contentInsetStartWithNavigation="0dp"app:layout_scrollFlags="enterAlways|scroll"app:popupTheme="@style/ThemeOverlay.AppCompat.ActionBar"app:subtitleTextAppearance="@style/Toolbar.SubTitle"app:theme="@style/ToolbarStyle"app:titleMarginStart="0dp"app:titleTextAppearance="@style/ToolBar.Title"tools:layout_height="50dp"tools:title="云阅" />
其中
theme
为:<style name="ToolbarStyle" parent="@style/ThemeOverlay.AppCompat.ActionBar"/>
,popupTheme
也不能设置单个的Light
或Dark
主题,不然切换深色模式的时候也不会改变效果。
6.WebView的深色模式设置
引入implementation 'androidx.webkit:webkit:1.2.0'
后可轻易的实现WebView的深色模式,不过有兼容问题,这和WebView的版本有关,WebView版本独立于Android版本。(亲测在系统6.0和7.1上无效。)
在有WebView的Activity的onCarete里加上如下代码:
WebSettings webSetting = webView.getSettings();
// 检查是否支持暗模式
if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) {boolean isAppDarkMode;if (NightModeUtil.getSystemMode()) {// 是否是跟随系统isAppDarkMode = NightModeUtil.isNightMode(this);} else {isAppDarkMode = NightModeUtil.getNightMode();}if (isAppDarkMode) {WebSettingsCompat.setForceDark(webSetting, WebSettingsCompat.FORCE_DARK_ON);} else {WebSettingsCompat.setForceDark(webSetting, WebSettingsCompat.FORCE_DARK_OFF);}
}
7.配置项
1).接下来就是一些配色和部分深色模式下的图片处理问题。
- 颜色:新建
values-night
文件夹,里面是深色模式下的colors.xml
文件 - 图片:新建
drawable-night-xxhdpi
图片文件夹
2).启动页我们经常会放品牌图,页面的深色模式可以通过 改变普通/深色模式文件夹下的图来实现。 会存在的问题:当系统是深色模式,应用里选择的是普通模式时,开屏图的背景是深色的。因为这时候还没有进入App,还没有初始化去设置模式。
3).也可以自己处理配置变更,不重建Activity:
<activityandroid:name=".NavNightModeActivity"android:configChanges="uiMode" />
当某个 Activity 声明它会处理配置变更时,系统会在出现主题背景变更时调用该 Activity 的 onConfigurationChanged()
方法。
val currentNightMode = configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
when (currentNightMode) {Configuration.UI_MODE_NIGHT_NO -> {} // Night mode is not active, we're using the light themeConfiguration.UI_MODE_NIGHT_YES -> {} // Night mode is active, we're using dark theme
}
遇到的问题
1).获取颜色ContextCompat.getColor(context, resId)
,需要加Activity
的context,如果是Application
的context会变不了色,这个和切换语言是一样的,获取String也不能用全局的context。
2).之前使用了关闭应用时杀掉进程的代码,导致不能重建Activity,找了好长时间问题。杀掉进程代码:android.os.Process.killProcess(android.os.Process.myPid());
3).如果代码需要单独动态设置ToolBar的主题:
// 设置toolbar的dark模式,为了使"完成"文字颜色显示白色
supportActionBar?.themedContext?.setTheme(R.style.ToolBarDarkActionBar)
4).可以使用系统自己的颜色值:
?android:attr/textColorPrimary
这是一种通用型文本颜色。它在浅色主题背景下接近于黑色,在深色主题背景下接近于白色。?android:attr/textColorSecondary
可作为第二文本颜色,相对于上面的颜色较浅。
5).在dialog打开后,再切换系统的深色模式,这时使用系统的颜色会不生效,需要使用自己的color文件里的颜色。具体出现在首次打开应用时,弹出的隐私弹框。
6).需要使用png后缀的图,最好别直接将jpg改为png,可以打开图片后将图片另存为png格式。我做时候debug模式下没问题,打release包的时候就提示了这个问题。
7).ViewModel里的page=1,不会被初始化,例如滑动到第二页后切换深色模式,page还是等于2,需要在onCreate里初始化page=1。
8).使用Glide时,不能直接获取颜色作为placeholder
使用,需要使用ContextCompat.getDrawable(context, resId);
Glide.with(imageView.getContext()).load(url).transition(DrawableTransitionOptions.withCrossFade(500)).placeholder(ContextCompat.getDrawable(imageView.getContext(), getDefaultPic(type))).error(ContextCompat.getDrawable(imageView.getContext(), getDefaultPic(type))).into(imageView);
总结
使用官方给出的深色模式Api,实现起来比较简单,但是也有一些注意项和优化点,如有需要可自取代码 GitHub:CloudReader,如有其他问题,欢迎留言骚扰~
Android 深色模式的项目应用相关推荐
- android自动切换暗色,超实用!Android 深色模式适配(可定时开启的APP内主题切换管理工具)...
前言 前面分享了一篇"黑白化主题"的文,主要适用场景是不久就要到来的"清明"等时节或者是其他的国家公祭日什么的(一名成熟的程序员,要学会自己提产品需求). 今天 ...
- Android深色模式适配原理分析,android应用开发
return when (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) { Configuration.UI ...
- Android深色模式下,看不见字的解决办法
你去看看,看不见字的那些是不是都没有设置字体颜色! 设置一下字体颜色就好啦! 对于AlertDialog,千万不要用它自己的,要我们自己写好view,然后设置view,不然的话,深色模式下,你是很难修 ...
- H5项目适配系统深色模式方案总结
文章目录 一.背景 二.问题 三.H5项目适配深色模式方案 1.声明 color-scheme 1.1meta 1.2CSS 2.通过 CSS 媒体查询 3.图片适配 4. JavaScript中判断 ...
- H5项目适配系统深色模式方案
一.背景 随着 iOS 13 的发布,深色模式(Dark Mode)越来越多地出现在大众的视野中,支持深色模式已经成为现代移动应用和网站的一个潮流,前段时间更是因为微信的适配再度引起热议.深色模式不仅 ...
- android开发适配深色模式,手机不支持深色模式,如何用软件解决深色模式的问题?(附有系统全局深色模式实现方法...
本帖最后由 巷子口的你 于 2020-8-8 07:57 编辑 1.92允许通过设置为助手应用来饮捷切频深色模式(设置入口一般为系统默认应用-助手和语音输人, MIU需要设置为语音助手)提醒:稳定模式 ...
- android自动切换暗色,Android 适配深色模式的总结
Android Q 推出了深色模式,其实 Android 9 就有了,部分厂商小米,三星就在系统 Android 9 加入了深色模式的开关. Android 提供了一套夜间模式主题,继承 Theme. ...
- android 9.0谷歌商店,Android 10现可选择Play商店主题模式 附Android 9强制开启深色模式教程...
不可否认的是自打苹果于去年推出配备深色模式的 iOS 13以来,整个移动互联网都开始流行起为应用配备深色模式设计的风气,不管用户个人到底喜不喜欢用深色模式,深色模式都已经给出了足够具有说服力的理由来推 ...
- line android 英文版,LINE 手機版也有深色模式啦!更新完我要去哪裡設定呢?Android/iOS 都有! (1/8 更新)...
發現大家都喜歡深色/暗黑模式,越來越多 App 的介面也開始提供黑色主題,現在 LINE 也有自己的深色模式啦-iPhone 與 Android 用戶將 LINE 手機版更新至最新版本後,就可以獲得全 ...
- 小米9android q测试版,小米9 Android Q Beta优先体验版已推送:新增深色模式
原标题:小米9 Android Q Beta优先体验版已推送:新增深色模式 7月12日消息,小米MIUI官方微博称,小米9的MIUI Android Q Beta优先体验版现已推送!已获得测试资格的小 ...
最新文章
- 03-老马jQuery教程-DOM操作(上)
- 关于mybatis里面的Executor--转载
- 如何将.sof转换成.jic
- 多媒体技术 PI 第一期:OSS 圆桌预告
- python中print的用法_Python中print函数简单使用总结
- 【转】各种树:trie树、B树、B-树、B+树、B*树
- Windows编译环境搭建(VS2010)
- Python模块之uuid
- aes js 加盐值 解密_cryptoJS AES 加解密简单使用
- 一行代码迁移TensorFlow 1.x到TensorFlow 2.0
- Linux gcc编译时强制链接并依赖一个库(即使未使用)
- pc 浏览器最小字体12px
- 基于三轴加速度传感器的老人摔倒检测
- MVC下压缩输入的HTML内容
- Maya多版本下载与激活方法
- Arduino使用u8g2库函数驱动4线/6线OLED屏幕(I2C/SPI通讯)附带库函数详解
- APP - 查询名下微信实名账户(可注销微信封号账户支付功能)
- android 仿微信加载框,Android自定义控件——仿微信半透明加载框
- Https 网站 访问 Http资源
- Benchmark测试——IOzone