“暗黑模式”之58 同城 iOS App深色模式适配实践

栏目: IT技术 · 发布时间: 4年前

内容简介:前言随着 iOS 13 和 Android 10 的正式发布,深色模式 (Dark Mode) 风靡一时。深色模式带来了酷炫的界面,更让人眼睛看起来非常舒服,如果用一个词来总结深色模式,那就是“赏心悦目”!目前业界已有不少App适配了深色模式,58 同城 iOS App 经过几个版本的迭代,在几个月前就已经上线深色模式。本文将通过深色模式适配缘由,深色模式适配设计目标,适配成果展示三方面,与大家分享 58 App 深色模式适配的经验与成果。

导语

“暗黑模式”最近赚足了话题。自 iOS 13 发布后,深色模式开始赚取眼球,3月22日,微信发布iOS新版本更新,正式支持深色模式。

关于深色模式, 58 同城 App  最近也做了很多探索和实践。本文总结了 58 同城 App 深色模式适配实践经验与成果,希望对您有所启发,让你的 App 开发的更加赏心悦目。

前言

随着 iOS 13 和 Android 10 的正式发布,深色模式 (Dark Mode) 风靡一时。深色模式带来了酷炫的界面,更让人眼睛看起来非常舒服,如果用一个词来总结深色模式,那就是“赏心悦目”!

目前业界已有不少App适配了深色模式,58 同城 iOS App 经过几个版本的迭代,在几个月前就已经上线深色模式。本文将通过深色模式适配缘由,深色模式适配设计目标,适配成果展示三方面,与大家分享 58 App 深色模式适配的经验与成果。

为什么适配深色模式

深色模式的适配,必然会带来开发成本的增加。要为 58 App 这样一个业务庞大、技术栈多样的应用适配深色模式,并不是一件容易的工作。为什么要适配深色模式,深色模式又能带来怎样的收益,是很多设计师、开发者、产品关心的问题。

1.  苹果推荐

深色模式是 iOS 13 推出的新特性,深色模式为 iOS 系统和各种 app 带来精美的深色配色方案。iOS 系统中,内置的 App 大都已适配深色模式,苹果强烈推荐开发者为自己的 App 适配深色模式。

2. 提升用户体验

深色模式不仅为 App 带来酷炫的深色配色方案,更有助于提升用户体验。在弱光环境下,深色模式的 App 让你的眼睛看起来舒服,而且更专注于内容,同时也不会打扰周围的人。

随着 iOS、Android 在系统层级对深色模式的支持,许多 App 也已逐步适配深色模式,未来越来越多的用户也将习惯并依赖于深色模式。试想一下,一个习惯了深色模式的用户,在一个宁静幽暗夜晚,突然切换到一个闪亮的 App,是多么糟糕的体验!

3. 业界趋势

在苹果推出深色模式之前,许多 App 业已支持夜间模式。谷歌在 Android 10 系统实现了对深色模式的支持,Flutter 1.12 也已完全支持 iOS 13 中的深色模式。随着 iOS、Android 两大手机操作系统对深色模式的完美支持,深色模式适配逐渐成为业界趋势,为自己的 App 适配深色模式也成为一项必要的工作。

目前业界的许多应用,包括淘宝 App、百度 App、QQ、爱奇艺、优酷等都已适配深色模式,就连曾不忍心占用用户珍贵夜晚的微信,也已向用户认怂,上线了深色模式。

4. 节省电量

深色模式不仅能为用户带来赏心悦目的体验,还能够节省电量,改善电池寿命。在 OLED 屏幕的手机(包括 iPhone 11 Pro, iPhone XS, and iPhone X)上,效果更加明显。

OLED 屏幕通过关闭相应的像素来产生纯黑色显示。这意味着在深色模式下,屏幕上的所有黑色区域都将被完全关闭,从而节省电池电量。

YouTube PhoneBuff 频道发布了一个实验视频,对比了 iPhone XS Max 在相同亮度下,浅色模式和深色模式下的电池使用情况。经过数小时的使用后,深色模式 iPhone 的电池电量剩余 43%,明显高于浅色模式 iPhone 的电池电量的 20%;当浅色模式的 iPhone 电量耗尽后,深色模式的 iPhone 电池电量还剩余 30%。

适配设计目标

对于 58 App 这样一个业务庞杂的大型App,适配深色模式并不是一件容易的工作。深色模式的适配涉及首页、部落、热议、招聘、租房、二手房、二手车、黄页、passport 等诸多业务线。58 App 的技术栈也相当复杂,页面包括 Navtive 页面、H5 页面、RN 页面,都需要适配深色模式。另外版本迭代节奏比较快,平均三周一个版本,要在一两个版本完成整个 App 的深色模式适配也不现实,我们通过几个版本的迭代,目前主路径页面已经完成深色模式适配,对于暂时未能适配深色模式的页面,通过自动添加蒙层,保障用户体验。为了减轻后续业务迭代成本,提高开发效率,我们设计样式库,逐步推广标准化组件。58 App 的深色模式适配设计目标主要考虑了以下几方面内容:

1. 如何应对复杂技术栈

58 App页面从技术上可以分为三类,Native 页面、RN 页面、Web 页面,三种页面深色模式适配技术上相互独立,却又紧密联系,整体流程设计如下图所示:

“暗黑模式”之58 同城 iOS App深色模式适配实践

图1 流程设计图

首先三类页面中,都存在由于开发资源和项目时间等因素限制,暂时未能适配深色模式的页面。为保证这些页面正常显示,让用户获得更好的用户体验,同时减轻业务线开发成本,由 Native 端统一添加蒙层。当 App 打开深色模式开关时,如果页面未适配深色模式,则自动添加蒙层;当跳转到适配深色模式的页面时,则移除蒙层。具体实现方案见“如何兼容不能参与适配功能”小节,此处不再赘述。

下面分别介绍 Native 页面、RN 页面、Web 页面深色模式适配技术方案:

Ø  Native 页面深色模式适配

为了兼容暂时未能适配的页面能够正常显示,我们通过 Runtime Method Swizzling 将页面默认重置为浅色样式。对于需要适配深色模式的页面,开发者首先需要在 viewDidLoad 方法中重置页面样式,使当前页面支持深色模式,示例代码如下:

- (void)viewDidLoad{

[super viewDidLoad];

if (@available(iOS 13.0, *)) {

self.overrideUserInterfaceStyle = UIUserInterfaceStyleUnspecified;

}

}

在页面支持深色模式后,接下来主要工作为修改视图背景色,文字颜色以及图片。 为提高开发效率,同时考虑后续业务迭代扩展成本,我们开发了样式库,样式库实现了颜色与图片的统一管理,规范了 UI 标准,为深色模式适配奠定了基础,具体设计参见“如何应对后续业务迭代成本”小节。

样式库提供了简单易用的 API,修改视图背景色,代码示例如下:

view.backgroundColor = [StyleLib colorWithType:@"Primary_1"];

为 UIImage 设置背景图片,示例如下:

UIImage* backImage = [StyleLib iconWithType:@"icon_back "];

Ø  RN页面深色模式适配

RN 页面为统一的载体页,在初始化时,Native 侧通过跳转协议或 Action 协议中相关参数,识别当初页面是否支持深色模式,设置当前载体页样式。同时将当前 App 样式,发消息给 RN 侧,渲染页面。

RN 组件适配深色模式,示例如下:

const styles = StyleSheet.create(

{ text: { fontSize: 16, color: ‘black’ } },

{ text: { color: ‘white’ } });


//fontSize: 16, color: ‘white’

< Text style={styles.text} >

RN 侧同时监听 App 显示状态,当 App 显示状态切换时,Native侧将当前样式发送至 RN 侧,RN 侧刷新渲染页面,实现逻辑如下:

MYAPP . addListener( ‘custom_dark_mode’ , mode => {

// 方案二:重启RN应用

MYAPP . applyUpdate( )

// 方案三:刷新RN应用

this . setState( { visible: false } ) ;

setTimeout ( ( ) => {

this . setState( { visible: true } ) ;

}, 0 ) ; });

方案二:重启RN应用。所有状态丢失,⻚面重新渲染。

方案三:刷新RN应用。原有状态保留,⻚面重新渲染。

Ø  Web页面深色模式适配

Web 页面同样在初始化时,通过跳转协议或 Action 协议参数,发送给 Hybrid 载体页,识别当初页面是否支持深色模式,设置当前载体页样式。Web 页实现相对简单,自己能够监听 App 显示状态,使用如下:

function myFunction(x) {

if (x.matches) { // 媒体查询

MYAPP.action.toast('dark')

} else {

MYAPP.action.toast('light')

}

}

var x = window.matchMedia("(prefers - color - scheme: dark)")

// 执行时调用的监听函数

myFunction(x)

// 状态改变时添加监听器 模式修改的时候触发

x.addListener(myFunction)

2. 如何应对大型 App 并行研发

58 App 迭代速度较快,通常三周一个版本。深色模式适配项目涉及首页、部落、热议、招聘、租房、二手房、二手车、黄页、passport 等诸多业务线,其中每个业务线有自已的日常业务开发和资源限制,另外随着 App 工厂项目的持续推进,一些基础组件和通用业务可能需要平移到其他应用。如何处理 58 App 中多业务线并行研发,甚至基础组件和通用业务的跨应用平移,都是在项目中要解决的问题。

为支撑多业务线并行研发,提高开发效率,深色模式适配框架分为基础层、服务层、业务层三层,架构设计如下:

“暗黑模式”之58 同城 iOS App深色模式适配实践

图2   架构设计图

基础层定义了样式库,主要包括颜色样式库、图片样式库、主题库,实现了图片、颜色、主题的统一管理,提供了简洁易用的 API,为深色模式适配奠定了基础。

服务层主要包括蒙层管理、跳转协议与 action 协议、控制开关。蒙层管理用于为暂时不支持深色模式的页面自动添加蒙层,优化用户体验;跳转协议、action 协议中定义了 RN 侧、Web 侧与 Native 端交互参数,用于控制页面显示样式。

控制开关在多业务并行研发过程中发挥着重要作用,控制开关分为 App 级与页面级两个粒度,能够灵活控制 App 及页面样式,为项目质量提供保障。项目开发初期,由于整体页面适配覆盖率较低,为保障用户体验,使用 App 级控制开关临时关闭深色模式。随时项目持续推进,整体效果碰到预期,我们再打开 App 级控制开关,如果仅有个别页面效果不佳,可以使用页面级控制开关,暂时关闭。

“暗黑模式”之58 同城 iOS App深色模式适配实践

图3 深色模式控制开关

58 App 中许多基础组件及通用业务,要随着 App 工厂项目平移到其他应用,在深色模式适配过程中,要考虑不同 App 间主题的兼容有以及其他应用开发编译环境兼容。关于基础组件主题样式间的兼容,可以参考“如何应对后续业务迭代成本”小节样式库的介绍。

在深色模式适配开发中,需要使用一些 iOS 13 新增的 API,如 setOverrideUserInterfaceStyle,如果不加编译控制,在低版本 Xcode 中,会导致编译失败。58 App 中许多公共组件,需要平移至集团其他 App 中,为兼容低版本 Xcode 编译,在使用 iOS 13 API 时,增加以下编译控制判断:

#if defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0

if (@available(iOS 13.0, *)) {

self.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;

}

#endif

3. 如何兼容不能参与适配功能

对于 58 App 这样大型复杂的应用,在短期内将所有的页面完成深色模式适配不太现实。由于各业务线有自己的开发任务和资源限制等因素,部分页面暂时不能支持适配。如何保障这些未适配的页面能够正常显示,并且最大可能的提升深色模式下用户体验,是我们设计过程中思考的一个重要问题。

Ø  兼容未适配深色模式的页面正常显示

Xcode 11默认开启了深色模式,一些使用系统默认颜色的视图,在切换到深色模式时,可能出现显示异常,如下图所示:

“暗黑模式”之58 同城 iOS App深色模式适配实践

图4 显示异常示意图

针对类似问题,苹果官方提供了解决方案,暂时不能支持深色模式适配的控制器、视图,可以将其 overrideUserInterfaceStyle 属性,设置为 UIUserInterfaceStyleLight 样式。解决方法看似简单,但要推动所有业务线去修改页面样式却并非易事,并且实施过程中还有可能遗漏。

为减轻业务线适配压力,提高开发效率,经过项目组讨论,最终我们选择使用 Objective-C  Runtime中的黑魔法 method swizzling 。通过 hook viewDidLoad 方法,在交换方法中,默认将 ViewController的overrideUserInterfaceStyle 属性重置为浅色样式,示例代码如下:

- (void)my_viewDidLoad{

if (@available(iOS 13.0, *)) {

if(NO == [self isSystemController]){

self.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;

}

}

[self my_viewDidLoad];

}

通过上述方案,确保即使未适配深色模式的页面,在用户切换到深色模式时,也能够正常显示。 需要适配深色的模式的页面,在相应的 viewDidLoad 方法中,重置 overrideUserInterfaceStyle 属性为默认样式即可。

在这里需要注意的是,不能简单粗暴的将所有的控制器重置为浅色样式。项目中会使用图片选择、文档选择等系统提供的功能,这些控制器已支持深色模式。为解决该问题,我们建立了名单管理机制,过滤掉那些以 UI 或下划线开头的系统类以及一些有特殊需求的业务类,使用默认样式。

另一个需要说明的问题是,上述代码只是重置了 ViewController 的样式,保证页面正常显示。一些直接添加到 Window 上视图仍然可能出现显示异常,在此同样可以选择 hook View 的相关方法,重置视图为浅色样式。Method swizzling 虽然功能强大,但还是尽可能选择慎用。经过权衡我们选择在工程是全局搜索添加到 window 上的相关代码,未能适配深色模式的视图,手动设置为浅色样式。

Ø    为未适配深色模式页面添加蒙层

在保证未适配深色模式的页面和视图能够显示正常显示后,为优化深色与浅色页面跳转过程中的用户体验,我们为未适配深色模式的页面添加了蒙层。

“暗黑模式”之58 同城 iOS App深色模式适配实践

图5 蒙层效果图

添加蒙层需要关注三个问题:

1)如何区分当前页面是否适配深色模式

要为未适配的页面添加蒙层,首先要区分哪些页面已适配深色模式,哪些页面未适配深色模式。我们已通过方法交换将所有页面默认重置为浅色样式,同时适配深色模式的页面,需要手动设置为默认样式。因此我们可以根据控制器的 overrideUserInterfaceStyle 属性判断一个页面,是否支持深色模式。

2)蒙层添加位置

在页面上添加蒙层,有两种方案:一是为每个控制器添加蒙层,这种方案比较灵活,便于页面自由定制,对于一些嵌套的控制器,需要特殊处理,实现起来相对复杂;另一种方案是在 Window 上添加蒙层,该方案实现起来比较简单,而且能够完全覆盖整个屏幕,体验更佳。因此我们选择在 Window 上添加蒙层。

3)蒙层显示隐藏时机

蒙层显示可以在 viewWillAppear 方法中,判断当前页面是否支持深色模式,如果不支持深色模式,则给当前页面添加蒙层;在 viewDidAppear 方法中,判断如果当前页面支持深色模式,则隐藏蒙层。

另外还需要监听系统显示模式切换,当系统切换到浅色模式时,移除蒙层;若系统切换到深色模式,并且当前控制器未适配深色模式,则需要显示蒙层。

4. 如何应对后续业务迭代成本

深色模式的适配需要修改调整大量页面和组件的颜色,如果仅仅为了适配深色模式,将所有的 UI 颜色修改一遍,这样耗时费力的修改工作的收益,值得我们思考。能否提供一套基础库,提升深色模式适配开发效率,同时减轻后续业务迭代成本,是我们设计过程中重点关注的另一个问题。

基于上述思考,我们设计了样式库。样式库不仅提供了简单易用的 API,方便业务方快速调整 UI 样式,适配深色模式;同时实现了 UI 样式的统一管理,让 UI 规范化、标准化,另外兼顾了 UI 组件标准化及跨应用平移,后续业务迭代成本及扩展,让深色模式适配项目更具价值。

样式库整体设计如下:

“暗黑模式”之58 同城 iOS App深色模式适配实践

图6 样式库设计

Ø    简单易用的 API

首先样式库,提供了一套简洁易用的 API,为深色模式的适配奠定了基础,提高了开发效率。在没有样式库之前,一个视图适配深色模式,调整背景色,示例代码如下:

view.backgroundColor = [UIColor lightColorWithHex:0xD9E2E9 lightColorAlpha:0.5 darkColorWithHex:0xFFFFFF darkColorAlpha:0.0];

基于样式库,修改视图背景色时,使用语义颜色,无论是否需要设置透明度,都可以这样写:

view.backgroundColor = [StyleLib colorWithType:@"Primary_1"];

Ø   颜色统一管理,灵活扩展换肤

在未使用样式库之前,颜色值硬编码于代码之中,修改组件颜色,需要大范围查找替换。 样式库对语义颜色与实际色值做映射存储,并对颜色实现了统一管理,让 UI 更加标准规范。 业务方不再允许使用硬编码的色值,而是直接使用语义颜色。 基于样式库,后续如果需要调整色值,只在样式库层调整即可,不再需要到处修改代码,减轻了后续修改成本。

样式库的建立同时为后期主题扩展提供了可行性,如果要扩展其他主题,只需要在样式库底层扩展主题,而业务层不需要大范围的修改,即可实现App 灵活换肤。

Ø   一次编码,多处运行

随着 58 App 工厂项目的快速持续推进,UI组件的跨业务复用,甚至跨应用平移实践场景也越来越多。通常不同的应用有着独自的设计风格,为实现 UI 组件的跨应用平移,样式库设计过程中,不同的 App 分别对应独立的主题库。真正实现了UI 组件的一次编码,多处运行,极大减轻了 UI 组件跨应用平移成本。

在深色模式适配项目中,我们已经实现了导航栏、通用弹窗、分享面板、Loading 框、筛选器等 UI 组件的标准化,后续我们将实现更多 UI 组件的标准化,推动业务方接入,减轻后续业务迭代及平移成本。

Ø   多套皮肤,一套设计

样式库不仅提高了开发效率,而且极大减轻了设计师的设计成本,对于多套主题,设计师只需提供一套设计。

样式库实现了颜色的统一管理,使 UI 更加标准规范,为深色模式的快速接入奠定了基础,深色模式的快速实现和上线更凸显了样式库的重大意义。将更多的 UI 组件统一到标准组件库中,实现组件集中化开发,UI 组件就能够实现跨业务,跨应用复用,极大提高业务开发效率和降低后续业务迭代及平移的成本。

适配成果展示及性能优化

1. Native 页面

“暗黑模式”之58 同城 iOS App深色模式适配实践

“暗黑模式”之58 同城 iOS App深色模式适配实践

图7  Native页面

2. RN 页面

“暗黑模式”之58 同城 iOS App深色模式适配实践

“暗黑模式”之58 同城 iOS App深色模式适配实践

图8  RN页面

3. Web 页面

“暗黑模式”之58 同城 iOS App深色模式适配实践

“暗黑模式”之58 同城 iOS App深色模式适配实践

图9  Web页面

4. 蒙层效果

“暗黑模式”之58 同城 iOS App深色模式适配实践

图10  蒙层效果

5. 耗电量对比

由于OLED屏幕中每个像素都是自主发光而非LCD由整个一块背光面板发光,所以在显示深色元素时像素所消耗的电流更低,尤其在纯黑颜色时像素点可以完全关闭达到省电的效果。目前,只有iPhone X、XS、XS MAX、11 Pro、11 Pro MAX 五款苹果手机使用的是OLED屏幕。

为此针对58同城App适配深色模式后对首页做了对比试验:

试验条件:

设备:iPhoneX  系统:iOS13.3

方法:打开58同城首页,设置Timer触发首页列表来回滚动。每掉电1%  就记录一下耗时。

试验结果:

横坐标:时间(分)

纵坐标:单位耗电量

“暗黑模式”之58 同城 iOS App深色模式适配实践

试验结论:

亮色模式下28分钟耗电约为:7.08 %

深色模式下28分钟耗电约为:5.32 %

深色模式下,基于58同城首页,整体耗电量相比亮色模式节约25%左右。

总结

深色模式是公司内部从设计到技术,一切从用户体验角度出发计划并实施的产物。为了让用户在58业务场景里在深色模式下有一致的体验,设计和技术上从Native页面到RN、Hybird页面进行了全面的适配。

在实施的过程中,遇到了很多困难。比较重要的难点是58业务较多,这个适配过程需要不同的业务线设计和技术进行沟通与协作。为了解决这些问题,设计上,统一了集团不同App间设计图上关于色值的定义与描述;同时技术上引入样式库,统一了App内不同业务线间对色值的使用方式,简化了亮色和暗色下调用,并彻底解决了长久以来不同业务间对颜色随意使用的局面。这样,使得用户在使用58App的过程中,具有一致的视觉体验。

后续,为了进一步提升用户体验,会和设计一同进行组件库的构建,组件库构建后不但能降低各业务线对组件适配深色模式的工作量,而且能统一App内组件的风格。而且对一些细节,在深色模式下会进一步打磨。因此,深色适配是其实是一个持续的项目。相信不久的将来,会积累更多深色模式的经验和心得分享给大家。

上述就是58 同城 App 深色模式适配目前的实践经验,由于作者水平有限,文中难免有疏漏之处,欢迎大家交流指正!

参考文献

1. WWDC: Implementing Dark Mode on iOS

2.  Supporting Dark Mode in Your Interface

3.  Choosing a Specific Interface Style for Your iOS App

4.  Switching your phone to dark mode could be a game-changer for your battery life, especially if you have one of 3 iPhones

作者简介

贾学文,58 同城 – 基础技术部 – iOS 技术部 高级研发工程师

蒋演,58 同城 – 基础技术部 – iOS 技术部 架构师

阅读推荐

1. 开源|Zucker:Android APP模块化大小自动分析统计工具

2. 开源|WBBlades:基于Mach-O文件解析的APP分析工具

5. 独家|浅谈对象序列化

“暗黑模式”之58 同城 iOS App深色模式适配实践


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

算法设计与分析基础

算法设计与分析基础

Anany Levitin / 清华大学出版社 / 2007-11 / 59.00元

作者基于丰富的教学经验,开发了一套对算法进行分类的新方法。这套方法站在通用问题求解策略的高度,能对现有的大多数算法进行准确分类,从而使读者能够沿着一条清晰的、一致的、连贯的思路来探索算法设计与分析这一迷人领域。本书作为第2版,相对第1版增加了新的习题,还增加了“迭代改进”一章,使得原来的分类方法更加完善。 本书十分适合作为算法设计和分析的基础教材,也适合任何有兴趣探究算法奥秘的读者使用,只要......一起来看看 《算法设计与分析基础》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

MD5 加密
MD5 加密

MD5 加密工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具