写点什么

优酷暗黑模式(八):分发场景落地(Android & iOS)

  • 2020-02-27
  • 本文字数:4502 字

    阅读完需:约 15 分钟

优酷暗黑模式(八):分发场景落地(Android & iOS)

一、背景介绍

随着 Android 10 与 iOS 13 先后支持暗黑模式,优酷客户端在完成了架构统一和组件标准化的工作之后,分发场景的复杂业务可以基于统一的技术方案进行暗黑模式的适配。

二、业务介绍

由于优酷业务分发场景业务复杂,承载页面众多(二十多种),在落地暗黑模式前,我们对优酷分发场景的业务进行了梳理,大致可以分为三类:


第一类是固定入口的页面,比如首页、频道、Feed 流、二级页,它们承接了分发场景的大部分业务,拥有样式丰富的组件库,它们的共性非常高。



第二类是独立业务方开发的二级页,这些二级页由垂直业务团队维护。由于优酷客户端已完成架构统一和组件标准化的工作,各个业务团队适配暗黑模式都是基于同一套技术方案,适配就变成了一个标准化的工作。业务团队只需按统一的方式适配即可,极大提高了开发效率。



第三类是一些历史遗留的一些老页面,这些页面没有固定的入口,入口分散在各个页面和各个组件, 适配暗黑模式成本相对较高。


这样的页面可以有两种处理方式:


  1. 流量小,非核心的分发场景,面临下线的业务不进行暗黑模式的适配。

  2. 有业务价值的页面进行迁移或合并,统一用新版的二级页承载。



三、暗黑适配

页面展现分几种状态:转场态, 加载态(Loading), 展现态,异常态。暗黑模式适配的主要工作是适配页面的展现态;转场态和加载态的生命周期虽然很短,但是不能忽略,否则很容易出现亮色-暗色页面状态的切换,会破坏整体的沉浸式浏览体验,异常态也是因为类似原因不能忽略。


1、页面级别

1) 顶部/底部导航/容器

顶部导航支持换背景色;底部导航支持换图片资源、文字颜色、背景颜色;容器支持背景色。



Android 示例代码


//获取下拉刷新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();
复制代码


iOS 示例代码


/// 暗黑变化回调/// @param manager 当前的主题管理对象/// @param identifier 当前主题的标志/// @param theme 当前主题对象- (void)ykn_themeDidChangeByManager:(YKNThemeManager *)manager identifier:(__kindof NSObject<NSCopying> *)identifier theme:(__kindof NSObject *)theme {    [super ykn_themeDidChangeByManager:manager identifier:identifier theme:theme];
// 顶部渐变色:深蓝渐变顶部Token CGColorRef topCGColor = UIColor.ykn_deepBlueGradientTopPoint.CGColor; // 底部渐变色:深蓝渐变底部Token CGColorRef midCGColor = UIColor.ykn_deepBlueGradientMiddlePoint.CGColor; if (topCGColor && midCGColor) { _gradientLayer.colors = @[(__bridge id)topCGColor, (__bridge id)midCGColor]; }}
复制代码

2) 页面/卡片/图片打底色

这里是比较容易遗漏的,Loading 态,错误态,打底图都需要适配,否则页面容易出现“白块”影响整体暗黑效果。



Android 示例代码


//从颜色管理器中取出背景色 YKN_PRIMARY_BACKGROUND 为 Design Token定义的色值int bgColor=ColorConfigureManager.getInstance().getColorMap().get(YKN_PRIMARY_BACKGROUND)setFragmentBackGroundColor(bgColor);
复制代码


加载骨架图通过 Android 系统的资源寻址自动获得。


我们只需建立暗黑模式的资源目录(night),并把骨架图的 drawble 放进去即可。


iOS 示例代码


// Feed流Loading图通过动态资源方式获取itemView.image = [UIImage ykn_home_feed_loading_default];
/// 首页Feed流默认Loading图+ (UIImage *)ykn_home_feed_loading_default { return [UIImage ykn_imageWithThemeProvider:^UIImage * _Nonnull(__kindof YKNThemeManager * _Nonnull manager, NSString * _Nullable identifier, NSObject<YKNThemeProtocol> * _Nullable theme) { // 暗黑模式下的图 if ([identifier isEqualToString:YKNThemeIdentifierDark]) { return [UIImage imageNamed:@"home_feed_loading_default_d"] ; } // 浅色模式下的图 return [UIImage imageNamed:@"home_feed_loading_default"]; }];}
复制代码

3) 暗黑与氛围/换肤的兼容问题

优酷分发场景支持换肤、氛围和暗黑模式,优先级为氛围>换肤>暗黑。所有页面、组件都在此规则上进行适配。


a) 页面同时存在氛围+暗黑


电影频道为了培养频道用户的心智,定义了头部和轮播的氛围色。



b) 页面整体都是氛围


高清频道突出高清适配的质感,将整个高清频道页面都定义了氛围色。


2、组件级别

分发场景有几十种组件,大部分组件接入非常便捷,只需将引用的资源字段改为 DesignToken 即可;

1) 常规组件

这里 Android 和 iOS 实现有些差异,需要分别说明。


a) Android



Android 为了提高性能,有些文本绘制使用了自定义 View 来单独绘制文本,目的是减少 View 数量和减少 View 的 measure 时间,上图的 PhoneCommonTitlesWidget 就是一个封装了标题绘制的自定义 View。


下面的代码主要是说明了如何使用 DesignToken,使用 DesignToken 色值有两种方式。


第一种,通过 Layout 布局文件使用包含 DesignToken 的 Style,这种方式方式一般用于系统控件,或继承自系统控件的简单封装比如 YKTextView:


 <com.youku.resource.widget.YKTextView        android:id="@+id/title_context_1"        style="@style/text_view_1a"   //style        android:layout_width="wrap_content"        android:layout_height="match_parent"        android:gravity="start|center_vertical"        android:layout_marginLeft="@dimen/dim_6"        app:layout_goneMarginLeft="0dp"        app:layout_constraintTop_toTopOf="parent"        app:layout_constraintBottom_toBottomOf="parent"        app:layout_constraintStart_toEndOf="@id/title_left_icon"        />
<style name="text_view_1a"> <item name="android:textSize">@dimen/font_size_big1</item> <item name="android:textStyle">bold</item> <item name="android:singleLine">true</item> <item name="android:includeFontPadding">false</item> <item name="android:ellipsize">end</item> <item name="android:textColor">@color/ykn_primary_info</item> //DesignToken颜色 </style>
复制代码


第二种,通过代码使用 DesignToken 色值,这种一般是自定义 View 通过 draw 的方式来渲染 UI,比如上图中的 PhoneCommonTitlesWidget。


 Resources res = context.getResources(); //主标题字体size int sDefaultTitleTextSize = res.getDimensionPixelSize(R.dimen.font_size_middle1); //副标题字体size int sDefaultSubtitleTextSize = res.getDimensionPixelSize(R.dimen.font_size_middle4); //主标题DesignToken颜色 int sDefaultTitleTextColor = res.getColor(R.color.ykn_primary_info); //副标题DesignToken颜色 int sDefaultSubtitleTextColor = res.getColor(R.color.ykn_tertiary_info);
复制代码


b) iOS



有些组件业务逻辑复杂、视图的层级很深,找到相应的代码非常耗时,我们可以使用 Xcode 的 Debug 工具、也可以使用优酷开发的一套 UI 检查工具(啄木鸟),来快速适配暗黑模式。


// 标题:一级信息色Token_titleLabel.textColor = [UIColor ykn_primaryInfo];
// 子标题:二级信息色Token_subtitleLabel.textColor = [UIColor ykn_secondaryInfo];
// 边框:升起的一级组块背景Token_borderView.backgroundColor = [UIColor ykn_elevatedPrimaryBackground];
复制代码

2)特殊组件

优酷有些组件展示的主体是服务端下发的图片,但是服务端暂时不支持下发视频暗黑模式的图片。针对这种组件就需要有个降级策略,尽量保证暗黑模式的整体显示效果,这种属于特例情况要根据自己的业务特性来定义降级模式。



下面是一个具体的样例。

四、遇到的问题

1、Android

由于资源(color,drawable)是通用的,对于那些没有适配暗黑的页面要进行特殊处理。具体方式是: 在暗黑模式下进入没有适配暗黑的页面, 需要关闭暗黑模式来保证页面可以寻址到亮色的资源,在离开的时候再恢复暗黑模式。


在进入页面的时候关闭暗黑模式,Activity OnResume 中调用下面代码,关闭暗黑模式


//判断当前是否处在暗黑模式if (UIMode.getInstance().isDarkMode()) {    //关闭暗黑模式    appCompatActivity.getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_NO);
//更新颜色配置 ColorConfigureManager.getInstance().onConfigureChanged();}
复制代码


在离开或页面不可见时候恢复暗黑模式,Activity OnPause 中调用下面代码,恢复暗黑模式


//判断当前是否处在暗黑模式 if (UIMode.getInstance().isDarkMode()) {    //恢复暗黑模式    appCompatActivity.getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_YES);} else {    //关闭暗黑模式    appCompatActivity.getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_NO);}
//更新颜色配置ColorConfigureManager.getInstance().onConfigureChanged();
复制代码

2、iOS

  1. 渐变色处理方式不友好


iOS 上渐变色无法自动切换暗黑样式,只能通过监听暗黑模式变化通知,手动设置暗黑渐变样式。


  1. 对比系统原生暗黑


五、适配效果

六、总结

暗黑模式对于视频类应用可以明显提升用户体验,在观感上更适合沉浸式的深度浏览,对于夜晚使用能有效避免亮色模式“刺眼”, 对眼睛更加舒适。因为 LED 屏幕在显示黑色像素的时候并不发光,因而可以提升续航时间,看剧更持久。


用户主路径涉及到的页面,弹窗,甚至图片默认打底图,Loading 图,页面加载出来前的骨架图尽量都适配暗黑模式。由于人眼对由暗到亮比由亮到暗更敏感(例如: 黑夜中突然的车灯会晃得睁不眼睛),主业务场景的暗黑模式尽量避免亮色模式的 UI 元素带来视觉反差,破坏用户沉浸式浏览观看体验。


对于 Android 而言,暗黑模式在系统级的支持是从 Android 10 开始,目前 Android 10 的手机还没有大规模的系统升级。在开发中我们可以通过代码强制打开暗黑模式,方便进行开发。产品上也可以考虑在客户端的设置项中增加“强制暗黑模式”的开关,使得低于 Android 10 版本的手机也可以使用暗黑模式。


作者简介


叔平,阿里文娱无线高级开发工程师。


相关阅读


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


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


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


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


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


优酷暗黑模式(六):暗黑模式的技术支撑 iOS


优酷暗黑模式(七):暗黑模式的技术支撑 Weex & H5


2020-02-27 15:001606

评论

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

开源一夏|要有遥不可及的梦想,也要有脚踏实地的本事

坚果

开源 HarmonyOS OpenHarmony 8月月更

小程序容器+自定义插件,可实现混合App快速开发

Speedoooo

小程序 插件 APP开发

一、《图解HTTP》- WEB和网络基础

懒时小窝

图解https

LeetCode第三题(Longest Substring Without Repeating Characters)三部曲之一:解题思路

程序员欣宸

LeetCode 8月月更

【高并发项目实战】自适应高并发复杂场景的订单拆分算法工具

小明Java问道之路

高可用 高并发 高性能 签约计划第三季 8月月更

鲲鹏编译调试插件实战

乌龟哥哥

8月月更

Java中的引用

flow

签约计划第三季

系统可用性:SRE口中的3个9,4个9...到底是个什么东西?

董哥的黑板报

运维 后端 可用性 SRE

PDF转Word有那么难吗?做一个文件转换器,都解决了

IC00

C# 签约计划第三季

Linux性能调优之内存负载调优的一些笔记

山河已无恙

签约计划第三季

【SeaTunnel】从一个数据集成组件演化成企业级的服务

Apache SeaTunnel

大数据 微服务 数据处理 数据集成 大数据 开源

好好活就是做有意义的事,有意义的事就是好好活

宇宙之一粟

8月月更

GRPC MacOS M1 处理器的问题

HoneyMoose

企业公众号文章写作方向:如何写出读者认可的优质内容

石头IT视角

如何给 UE4 场景添加游戏角色

HelloWorld杰少

c++ 游戏 UE5 8月月更

SRv6 L3VPN的工作原理

穿过生命散发芬芳

8月月更 SRv6

学习英语的网站与资料

玄兴梦影

学习 英语

微软校园大使喊你来秋招啦!

DawnMagnet

让你10分钟就能看懂Linux文件权限(超级详细、超级简单!!!)

Albert Edison

Linux centos linux 文件权限控制 8月月更

前端食堂技术周刊第 46 期:Chrome 三方 cookie 计划、npm 引入更多安全增强功能、Awesome Bun

童欧巴

Linux npm Cookie

【Go实现】实践GoF的23种设计模式:迭代器模式

元闰子

Go 设计模式 迭代器模式

Nacos配置中心之加载配置

急需上岸的小谢

8月月更

Python 教程之输入输出(1)—— 在 Python 中接受输入

海拥(haiyong.site)

Python 8月月更

如何优雅的消除系统重复代码

慕枫技术笔记

设计模式 代码 签约计划第三季 8月月更

你认同这个观点吗?大多数企业的数字化都只是为了缓解焦虑

雨果

数字化转型 数字化

Android编译系统初探

桑榆

8月月更

Serverless基础知识

阿泽🧸

Serverless 8月月更

毕业作业-设计电商秒杀系统

Fan

#架构实战营

dvwa 通关记录1 - 暴力破解 Brute Force

Todd-Lee

渗透测试 DVWA

物无定味适口者珍,Python3并发场景(CPU密集/IO密集)任务的并发方式的场景抉择(多线程threading/多进程multiprocessing/协程asyncio)

刘悦的技术博客

多线程 协程 多进程 Python3 Python.

leetcode 204. Count Primes 计数质数 (Easy)

okokabcd

LeetCode 算法与数据结构

优酷暗黑模式(八):分发场景落地(Android & iOS)_移动_阿里巴巴文娱技术_InfoQ精选文章