【ArchSummit】如何通过AIOps推动可量化的业务价值增长和效率提升?>>> 了解详情
写点什么

优酷暗黑模式(五):暗黑模式的技术实现策略

  • 2020-02-26
  • 本文字数:4964 字

    阅读完需:约 16 分钟

优酷暗黑模式(五):暗黑模式的技术实现策略

正如本系列第一篇文章所介绍的,Google 是从 Android 10 正式发布了对暗黑模式的支持,之前随公众理解的深色氛围一跃而上成为系统平台级能力。暗黑模式带给了我们什么呢?


  • 深色界面在专注环境下与内容有更高的契合度,更凸显内容、缓解视觉疲劳;

  • 深色界面更易营造品质感与沉浸感;

  • 深色界面更易建立填充感。

一、暗黑模式项目背景

暗黑模式作为一种系统平台能力,它打造的是整个用户使用周期的全链路视觉体验,也就是要覆盖到用户能到达的每一个角落。


这包括了分发场景,搜索场景,消费场景等复杂的页面结构,也包括二级落地页,活动页等独立页面; 还包括了弹窗,Toast,播放器等常用组件。要全面覆盖如此复杂细碎的场景,需要实现整体性的视觉呈现效果和低成本的全局平台开关。



分析完暗黑模式的影响范围,我们再来看一下我们实践的对象-优酷 APP。优酷 App 发展到今天,已经从一个单体 App,进化成了一个承载集团众多业务出口的超级 App。所以优酷 App 的页面是由十几个完整建制的内部和外部团队共同开发和维护的。


暗黑模式这种全站范围的适配将涉及到上百位设计/开发/测试同学,管理成本,沟通和协调成本,最终落地成本都非常高。


对于这种全站规格的需求,以往优酷的经验是会大量占用业务需求的开发人力,甚至会因此 delay 部分业务需求。这种开发模式是很难延续,不可接受的,本次暗黑模式的适配,我们既希望在第一时间将暗黑模式呈现给客户的,也希望能以更低的成本来完成项目需求。


这给项目方案提出了很大的挑战,但是得益于优酷之前已经实施了设计标准化体系,因此我们有信心和底气完成这些挑战。

二、暗黑模式在优酷的实践

首先,得益于优酷设计标准化体系的落地,我们已经提炼出公共资源库,构建了多层的 DesignToken 体系; 并对大部分一级页面的业务组件进行了接入。所以我们的工作就变成了两部分,一部分是已经接入设计标准化的视觉元素,这部分可以通过修改公共资源库中的 Token 定义,直接添加对暗黑模式的支持,零成本完成适配。另一部分则是扩大设计标准化体系的覆盖范围,在适配暗黑模式的同时,完成更多业务的技术架构的基础建设。


其次,我们还对于暗黑模式进行了色彩分层,静态色层是全站使用的基础色值,它直接对应着一个具体的值。它不会随着视觉模式的变化而变化。在它之上的是动态色层,动态色在不同的视觉模式下,对应不同的静态色。这是通过 Android 原生的资源加载机制完成: 即暗黑模式对应关系在暗黑资源文件中,普通模式在普通资源文件夹中。


在动态色层之上,是代码编写的色彩管理器,它在合适的时间会去获取当前的所有静态/动态色值。设计这一层有两个原因: 一个是提高性能,提前缓存一份给更上层调用,另一个是形成中间层。


众所周知,XML 资源文件的动态性是不足的。XML 资源启动即加载,加载后就是只读的。有了这一层,我们可以支持服务端动态下发色值 Token 的定义,以达成一定程度的动态性。


在色彩管理器之上,是公共的控件和组件层。有了这样的层次关系,使最终的业务设计可以通过搭建完成,完全不需要从零写起,也不需要关注设计标注的细节,开发再也不用逐个元素的调整,设计也不需要逐个像素的校对。只要在第一次纳入的时候进行一次就可以完成,大幅提高了工作效率。



静态 Token:



动态 Token:


动态色对照表



在实际的适配中,布局文件中需要注意的是要使用 Token 来设置组件属性,而在代码中则可以通过公共资源库中提供的工具方法 UIMode.isDarkMode()来读取当前是否是暗黑模式,通过 ColorConfigureManager.getInstance().getColorMap().get(token 名)来获得色值。


具体的适配工作可以看后面的相关文章。08 暗黑模式在优酷分发场景的落地、09 暗黑模式在优酷消费场景的落地 Android。


下面是暗黑模式适配的示例代码:


<?xml version="1.0" encoding="utf-8"?><com.youku.resource.widget.YKRatioLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="@dimen/resource_size_102"    android:layout_height="@dimen/resource_size_153"    android:gravity="center"    android:orientation="vertical"    app:picRatio="p2s1"    android:id="@+id/yk_item_more_layout"    android:background="@color/ykn_secondary_background">
<com.youku.resource.widget.YKTextView android:id="@+id/yk_item_more" android:layout_width="wrap_content" android:layout_height="wrap_content" style="@style/text_view_7b" android:gravity="center" android:drawableRight="@drawable/yk_title_nav_icon" android:text="更多"/></com.youku.resource.widget.YKRatioLinearLayout>

//获取下拉刷新DesignToken色值int refresBgColor = ColorConfigureManager.getInstance().getColorMap().get(YKN_DEEP_BLUE_GRADIENT_MIDDLE_POINT);//设置下拉刷新mYkClassicsHeader.setBgColor(refresBgColor);
//获取顶部导航背景资源,对应android来说都是一个命名,暗黑模式的资源单独放在night目录下int defaultImage = R.drawable.yk_top_bg;//设置顶部导航背景setPlaceHoldForeground(getResources().getDrawable(defaultImage));
//获取页面背景色int backGroundColor=ColorConfigureManager.getInstance().getColorMap().get(YKN_PRIMARY_BACKGROUND);//设置页面背景色setFragmentBackGroundColor();
复制代码


此外,我们在适配暗黑的过程中,还遇到了很多具体的问题,比如

1、低版本 Android 系统如何支持暗黑模式

虽然 Google 是在 Android 10 的版本中才默认添加了暗黑模式的切换开关,但是,在之前的系统版本中已经预埋了对暗黑资源文件夹的加载能力; 而且有一部分厂商如小米就在 Android 9 的 MIUI 定制版本中提供了切换"暗黑模式"的开关。


所以对于低版本的用户,我们也提供了适配方案。具体来说,我们是通过调用系统 API


AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO/MODE_NIGHT_YES);
复制代码


来触发模式切换的。


需要特别注意的是,使用这个函数是有一些坑的。比如,在使用它之后,如果没有在 Activity 的 manifest 文件中增加


android:configChanges=“UIMODE”


的话,在 Activity 转屏也会引起 Activity 重建。


一般的 Activity 开发逻辑可能不会考虑到这种场景,很多逻辑在这里是会引发 Bug 的。

2、如何监视暗黑模式的切换

可以通过 onConfigurationChanged 进行监听。


这里一般有两种情况:


一种是活动需要监听它,来进行手动刷新,这时需要在 manifest 文件增加上面的配置。才能够监听到系统回调。


另一种是某个控件或组件,或者我们的全局状态,可能需要独立监听,这种情况按下面的代码进行监听。


getApplication().registerComponentCallbacks(new ComponentCallbacks() {        @Override        public void onConfigurationChanged(Configuration newConfig) {        //do something        }}
复制代码

3、系统刷新和手动刷新

暗黑模式的切换必然需要重新渲染页面,这里我们分两种刷新方式:


一种是直接交给系统,系统会在切换是重建 Activity 从而引发页面重新渲染。这种适合"用户使用行为不需要记录状态"的 Native 页面,和 Weex/H5 等动态页面。缺点就是会丢失用户之前的视觉锚点。


另一种, 则是自己监听 onConfigurationChanged 事件然后手动进行有目的范围的"局部刷新"。比如优酷 App 中的播放页。请参考《极致酷黑: 优酷暗黑模式实现系列 – (9)暗黑模式在优酷消费场景的落地 Android》

4、设计体系未覆盖的老旧页面如何适配

在众多的页面中,有一些老旧的页面改造成本过高,甚至已无人维护。


如果不作任何处理的话,这些页面会因为同时使用已改造组件和未改造组件而造成不同视觉模式同时出现。为了了避免这种情况的发生,我们会在页面进入时,强制指定页面的视觉模式方法是:


getDelegate().setLocalNightMode(MODE_NIGHT_YES/MODE_NIGHT_NO);
复制代码


这个 API 的作用范围是所属的 Activity。

三、未来的展望

我们认为,设计标准化体系大大的提高了类似"暗黑模式"这种全站视觉变更项目的效率,DesignToken 的设计将开发从繁琐的视觉效果开发中解脱了出来。


优酷的暗黑模式适配在两周之内顺利完成,并且没有影响同期的产品需求。未来我们会继续深化和丰富标准化设计体系的能力,也希望这种开发方式可以在不同的 App 间变成通用的开发范式。


设计标准化体系的开发,对于公共组件池的跨应用使用,Weex/Flutter/小程序等的跨应用通投都有重要的参考意义。


作者简介


涵父,阿里文娱无线开发专家。


相关阅读


优酷暗黑模式(一):是什么、为什么、如何落地?


优酷暗黑模式(二):如何建立设计语言标准化管理体系


优酷暗黑模式(三):暗黑模式设计指南


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


2020-02-26 10:002104

评论

发布
暂无评论
发现更多内容

SAP MM SPED输出报错-No authorization for delivery from shipping point US##-之对策

SAP虾客

SAP MM SPED VL31N 公司间STO

SRE运维解密-应对过载

董哥的黑板报

微服务 SRE 限流 SRE实践

【web 开发基础】PHP 中的预定义数组详解之一 (47)

迷彩

数组 全局变量 PHP基础 预定义数组

为什么更推荐使用组合而非继承关系?

JAVA旭阳

Java 架构

设计模式之美——里式替换(LSP)

GalaxyCreater

设计模式

Flink 在米哈游的应用实践

Apache Flink

大数据 flink 实时计算

超越10倍开发者

俞凡

研发效能

还在手动发早安,教你用java实现每日给女友微信发送早安

华为云开发者联盟

Java 开发 代码 华为云 12 月 PK 榜

【FAQ】在华为鸿蒙车机上集成华为帐号的常见问题总结

HMS Core

HMS Core

华为云CodeArts Req需求管理工具,7大特性限时免费体验

华为云开发者联盟

需求管理 开发 华为云 12 月 PK 榜

FFA 2022 主会场 Keynote:Flink Towards Streaming Data Warehouse

Apache Flink

大数据 flink 实时计算

项目管理系统哪最好?

PingCode

YOLOv5全面解析教程②:如何制作训练效果更好的数据集

OneFlow

人工智能 深度学习 数据集

WEB21

Lenyi

网络安全 CTF ctfshow 爆破

模块三-外包学生管理系统的架构文档

悟空

学生管理系统架构

WEB23

Lenyi

网络安全 CTF ctfshow 爆破

基于随机森林算法进行硬盘故障预测

华为云开发者联盟

人工智能 机器学习 华为云 12 月 PK 榜

极客时间运维训练营第九周作业

好吃不贵

2022-12-24:给定一个字符串s,其中都是英文小写字母, 如果s中的子串含有的每种字符都是偶数个, 那么这样的子串就是达标子串,子串要求是连续串。 返回s中达标子串的最大长度。 1 <= s的长

福大大架构师每日一题

Linux 算法 Shell 福大大

ChatGPT进化的秘密

OneFlow

人工智能 机器学习 深度学习 GPT

Zebec Chain缘何能成为新晋应用链,熊市下又为何值得我们关注?

EOSdreamer111

Java中Map集合的三种遍历方式

@下一站

Java 程序设计 map 12月日更 12月月更

Flink 1.16:Hive SQL 如何平迁到 Flink SQL

Apache Flink

大数据 flink 实时计算

MMEval正式支持OneFlow评测

OneFlow

机器学习 深度学习 算法

Zebec Chain缘何能成为新晋应用链,熊市下又为何值得我们关注?

股市老人

Android Studio开发Android APP

攻城狮Wayne

Android Studio 开发环境 新建工程

设计模式之美——对扩展开放、对修改关闭

GalaxyCreater

设计模式

OpenTelemetry系列 (四)| 如何使用Java Agent来实现无侵入的调用链

骑牛上青山

Java javaagent 调用链 OpenTelemetry 微服务调用链

架构误区系列9:强扭的「复用」

agnostic

【Java基础】Win10如何配置jdk环境变量(配置java环境变量)

No8g攻城狮

Java、 java 并发 Java IO

HTTP通用首部字段

穿过生命散发芬芳

HTTP 12月月更

优酷暗黑模式(五):暗黑模式的技术实现策略_移动_阿里巴巴文娱技术_InfoQ精选文章