我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android夜间模式最佳实践

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android夜间模式最佳实践

由于Android的设置中并没有夜间模式的选项,对于喜欢睡前玩手机的用户,只能简单的调节手机屏幕亮度来改善体验。目前越来越多的应用开始把夜间模式加到自家应用中,没准不久google也会把这项功能添加到Android系统中吧。

业内关于夜间模式的实现,有两种主流方案,各有其利弊,我较为推崇第三种方案:

1、通过切换theme来实现夜间模式。
2、通过资源id映射的方式来实现夜间模式。
3、通过修改uiMode来切换夜间模式。

值得一提的是,上面提到的几种方案,都是资源内嵌在Apk中的方案,像新浪微博那种需要通过下载方式实现的夜间模式方案,网上有很多介绍,这里不去讨论。

下面简要描述下几种方案的实现原理:

一、通过切换theme来实现夜间模式

首先在attrs.xml中,为需要随theme变化的内容定义属性


<?xml version="1.0" encoding="utf-8"?>
<resources>
  <attr name="textColor" format="color|reference" />
  <attr name="mainBackground" format="color|reference" />
</resources>

其次在不同的theme中,对属性设置不同的值,在styles.xml中定义theme如下


<?xml version="1.0" encoding="utf-8"?>
<resources>
  <!-- 默认 -->
  <style name="ThemeDefault" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="mainBackground">#ffffff</item>
    <item name="textColor">#000000</item>
  </style>
  <!-- 夜间 -->
  <style name="ThemeNight" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="mainBackground">#000000</item>
    <item name="textColor">#ffffff</item>
  </style>
</resources>

在布局文件中使用对应的值,通过?attr/属性名,来获取不同theme对应的值。


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android="@+id/main_screen"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical"
  android:background="?attr/mainBackground">
  <Button
    android:id="@+id/button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:text="改变Theme"
    android:onClick="changeTheme"
    android:textColor="?attr/textColor"/>
</LinearLayout>

在Activity中调用如下changeTheme方法,其中isNightMode为一个全局变量用来标记当前是否为夜间模式,在设置完theme后,还需要调用restartActivity或者setContentView重新刷新UI。


public void changeTheme() {
  if (isNightMode) {
    setTheme(R.style.ThemeDefault);
    isNightMode = false;
  } else {
    setTheme(R.style.ThemeNight);
    isNightMode = true;
  }
  setContentView(R.layout.activity_main);
}

到此即完成了一个夜间模式的简单实现,包括Google自家在内的很多应用都是采用此种方式实现夜间模式的,这应该也是Android官方推荐的方式。

但这种方式有一些不足,规模较大的应用,需要随theme变化的属性会很多,都需要逐一定义,有点麻烦,另外一个缺点是要使得新theme生效,一般需要restartActivity来切换UI,会导致切换主题时界面闪烁。

不过也可以通过调用如下updateTheme方法,只更新需要更新的部分,规避闪烁问题,只是需要写上一堆updateTheme方法。


private void updateTheme() {
  TypedValue typedValue = new TypedValue();
  Resources.Theme theme = getTheme();
  theme.resolveAttribute(R.attr.textColor, typedValue, true);
  findViewById(R.id.button).setBackgroundColor(typedValue.data);
  theme.resolveAttribute(R.attr.mainBackground, typedValue, true);
  findViewById(R.id.main_screen).setBackgroundColor(typedValue.data);
}

二、通过资源id映射的方式实现夜间模式

通过id获取资源时,先将其转换为夜间模式对应id,再通过Resources来获取对应的资源。


public static Drawable getDrawable(Context context, int id) {
  return context.getResources().getDrawable(getResId(id));
}
public static int getResId(int defaultResId) {
  if (!isNightMode()) {
    return defaultResId;
  }
  if (sResourceMap == null) {
    buildResourceMap();
  }
  int themedResId = sResourceMap.get(defaultResId);
  return themedResId == 0 ? defaultResId : themedResId;
}

这里是通过HashMap将白天模式的resId和夜间模式的resId来一一对应起来的。


private static void buildResourceMap() {
  sResourceMap = new SparseIntArray();
  sResourceMap.put(R.drawable.common_background, R.drawable.common_background_night);
  // ...
}

这个方案简单粗暴,麻烦的地方和第一种方案一样:每次添加资源都需要建立映射关系,刷新UI的方式也与第一种方案类似,貌似今日头条,网易新闻客户端等主流新闻阅读应用都是通过这种方式实现的夜间模式。

三、通过修改uiMode来切换夜间模式

首先将获取资源的地方统一起来,使用Application对应的Resources,在Application的onCreate中调用ResourcesManager的init方法将其初始化。


public static void init(Context context) {
  sRes = context.getResources();
}


切换夜间模式时,通过更新uiMode来更新Resources的配置,系统会根据其uiMode读取对应night下的资源,同时在res中给夜间模式的资源添加-night后缀,比如values-night,drawable-night。


public static void updateNightMode(boolean on) {
  DisplayMetrics dm = sRes.getDisplayMetrics();
  Configuration config = sRes.getConfiguration();
  config.uiMode &= ~Configuration.UI_MODE_NIGHT_MASK;
  config.uiMode |= on ? Configuration.UI_MODE_NIGHT_YES : Configuration.UI_MODE_NIGHT_NO;
  sRes.updateConfiguration(config, dm);
}

至于Android的资源读取,我们可以参考老罗的博客《Android应用程序资源的查找过程》,分析看看资源是怎么被精准找到的。这种方法相对前两种的好处就是资源添加非常简单清晰,但是UI上的更新还是无法做到非常顺滑的切换。

我是怎么找到第三种方案的?

在Android开发文档中搜索night发现如下,可以通过UiModeManager来实现

night: Night time
notnight: Day time
Added in API level 8.

This can change during the life of your application if night mode is left in auto mode (default), in which case the mode changes based on the time of day. You can enable or disable this mode using UiModeManager. See Handling Runtime Changes for information about how this affects your application during runtime.

不幸的是必须在驾驶模式下才有效,那是不是打开驾驶模式再设置呢,实际上是不可行的,驾驶模式下系统UI有变动,这样是不可取的。



public void setNightMode(int mode)

从源码开始看起,UiModeManagerService.java的setNightMode方法中:


if (isDoingNightModeLocked() && mNightMode != mode) {
  Settings.Secure.putInt(getContext().getContentResolver(), Settings.Secure.UI_NIGHT_MODE, mode);
  mNightMode = mode;
  updateLocked(0, 0);
}
boolean isDoingNightModeLocked() {
  return mCarModeEnabled || mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED;
}

在 isDoingNightModeLocked中判断了DockState和mCardMode的状态,如果满足条件实际上只修改了mNightMode的值,继续跟踪updateLocked方法,可以看到在updateConfigurationLocked中更新了Configuration的uiMode。

让我们转向Configuration的uiMode的描述:



public int uiMode;

uiMode为public可以直接设置,既然UiModeManager设置nightMode只改了Configuration的uiMode,那我们是不是可以直接改其uiMode呢?

实际上只需要上面一小段代码就可以实现了,但如果不去查看UiModeManager的夜间模式的实现,不会想到只需要更新Configuration的uiMode就可以了。

您可能感兴趣的文章:android基础教程之夜间模式实现示例Android实现日夜间模式的深入理解Android 实现夜间模式的快速简单方法实例详解三行Android代码实现白天夜间模式流畅切换Android主题切换之探究白天和夜间模式Android实现夜间模式切换功能实现代码Android 夜间模式的实现代码示例Android编程实现夜间模式的方法小结


免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android夜间模式最佳实践

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android夜间模式最佳实践

由于Android的设置中并没有夜间模式的选项,对于喜欢睡前玩手机的用户,只能简单的调节手机屏幕亮度来改善体验。目前越来越多的应用开始把夜间模式加到自家应用中,没准不久google也会把这项功能添加到Android系统中吧。 业内关于夜间模
2022-06-06

android夜间模式如何实现

要实现Android夜间模式,可以按照以下步骤操作:1. 创建不同的主题资源:在`res/values/`目录下创建一个`themes.xml`文件,并在其中定义两个主题,一个是默认主题,一个是夜间主题。例如:```xml```2. 在`A
2023-09-08

PHP设计模式:最佳实践探究

设计模式在 php 中提供可重复的代码解决方案,提高代码的可维护性、可扩展性和可复用性。常见的模式包括:单例模式:确保只创建一个类的实例。观察者模式:允许一个对象通知多个对象其状态更改。工厂方法模式:通过接口创建对象,将对象的创建与实现分离
PHP设计模式:最佳实践探究
2024-05-13

Android 夜间模式的实现代码示例

夜间模式实现所谓的夜间模式,就是能够根据不同的设定,呈现不同风格的界面给用户,而且晚上看着不伤眼睛,实现方式也就是所谓的换肤(主题切换)。对于夜间模式的实现网上流传了很多种方式。也反编译了几个新闻类(你懂得)夜间模式实现的比较的好的App,
2022-06-06

Android实现日夜间模式的深入理解

在本篇文章中给出了三种实现日间/夜间模式切换的方案,三种方案综合起来可能导致文章的篇幅过长,请耐心阅读。 1、使用 setTheme 的方法让 Activity 重新设置主题; 2、设置 Android Support Lib
2022-06-06

如何在Android应用中实现夜间模式

如何在Android应用中实现夜间模式?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。夜间模式实现所谓的夜间模式,就是能够根据不同的设定,呈现不同风格的界面给用户,而且晚上看
2023-05-31

PHP 函数最佳实践和设计模式

php最佳实践:遵循驼峰命名法。使用类型提示。确保函数短小精悍。避免副作用。使用文档注释。设计模式:单例模式:确保单个实例。工厂模式:创建对象。观察者模式:订阅事件。适配器模式:兼容接口。代理模式:提供代理。PHP 函数最佳实践和设计模式
PHP 函数最佳实践和设计模式
2024-04-12

PHP 函数设计模式和最佳实践

了解 php 函数设计模式和最佳实践:设计模式:工厂模式:允许在运行时创建不同类型的对象。单例模式:确保一个类只有一个实例。最佳实践:命名约定:使用清晰、简洁的函数名。单一职责原则:函数仅执行一项任务。参数类型提示:指定参数和返回值类型。默
PHP 函数设计模式和最佳实践
2024-04-30

Android实现夜间模式切换功能实现代码

现在很多App都有夜间模式,特别是阅读类的App,夜间模式现在已经是阅读类App的标配了,事实上,日间模式与夜间模式就是给App定义并应用两套不同颜色的主题,用户可以自动或者手动的开启,今天用Android自带的support包来实现夜间模
2022-06-06

PHP 单元测试反模式与最佳实践

php单元测试的反模式包括依赖外部服务、测试实现细节以及过多的断言。最佳实践建议使用桩件替代外部服务、专注于公共接口、通过白盒测试深入检查代码、关注有意义的覆盖率和将断言分组到逻辑单元中。利用mockery等桩件框架可以增强测试的可靠性。P
PHP 单元测试反模式与最佳实践
2024-05-07

PHP 设计模式单元测试最佳实践

php 设计模式单元测试最佳实践:隔离依赖项: 使用依赖注入或 mock 对象,避免与外部组件的耦合。测试边界条件: 考虑异常、错误处理和边缘用例,确保设计模式在各种情况下都能正确工作。覆盖多种场景: 测试不同变体和实现,以涵盖所有可能的行
PHP 设计模式单元测试最佳实践
2024-05-07

android基础教程之夜间模式实现示例

代码如下:package org.david.dayandnightdemo.cor; import android.os.Bundle;import android.app.Activity;import android.content.
2022-06-06

Android异常处理最佳实践

一个好的app 异常处理机制 我认为应该至少包含以下几个功能: 1.能把错误信息上传到服务器 让开发者可以持续改进app 2.错误信息至少应该包含 是否在主进程 是否在主线程 等可以帮助程序员定位的信息 3.最好包含手机硬件及软件信息。
2022-06-06

Golang Facade模式与快速开发的最佳实践

Golang中的Facade模式是一种结构型设计模式,用于提供一个简化的接口,以便客户端可以更轻松地使用复杂的子系统。它通过将子系统的组件封装在一个单独的接口中,为客户端提供一种简化的方式来与这些组件进行交互。以下是Golang中Facad
2023-10-08

Golang函数库的最佳实践和设计模式

go 函数库设计最佳实践包括:模块化、明确接口、清晰文档、错误处理、谨慎使用类型断言。常用的设计模式包括:单例模式(确保单一实例)、工厂模式(创建对象变体)、依赖注入(解耦组件)。遵循这些原则可以打造模块化、可维护、可扩展且不易出错的函数库
Golang函数库的最佳实践和设计模式
2024-04-18

Golang Facade模式的灵活应用与最佳实践

Golang中的Facade模式可以用于将复杂的子系统封装起来,提供一个简单的接口供客户端使用。这个模式可以提供灵活的应用,并且有一些最佳实践可以遵循。以下是Golang中Facade模式的灵活应用与最佳实践:1. 封装复杂的子系统:Fac
2023-10-10

函数异常处理的最佳实践和模式

函数异常处理的最佳实践和模式在编写代码时,异常处理对于确保应用程序的健壮性和可靠性至关重要。通过遵循最佳实践和模式,你可以有效地处理错误情况和异常。最佳实践1. 使用 try-catch 块:try-catch 块用于捕获并处理可能发
函数异常处理的最佳实践和模式
2024-04-13

PHP 函数调用中的最佳实践与反模式

最佳实践:1. 使用命名空间和别名减少冗余。2. 使用可选参数提高灵活性。3. 进行参数类型检查增强健壮性。反模式:1. 滥用别名和重复命名空间。2. 缺少类型检查会降低可靠性。PHP 函数调用中的最佳实践与反模式最佳实践使用命名空间:使
PHP 函数调用中的最佳实践与反模式
2024-04-17

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录