GMTC北京站9折购票倒计时,部分日程已上线,戳此查看 了解详情
写点什么

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

  • 2020 年 2 月 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 年 2 月 27 日 15:001094

评论

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

架构师训练营 1 期 - 第七周 - 性能优化1

三板斧

极客大学架构师训练营

第七周

Geek_fabd84

Web 性能压测工具

A p7+

架构师训练营 总结3

Arthur

极客大学架构师训练营

第三周学习总结

tothegump

极客大学架构师训练营

区块链与机械时钟的演化

CECBC

区块链

Week3-面向对象的设计模式(作业一)

shuyaxx

作业-第3周

arcyao

架构师训练营 Week7 - 性能优化 - 性能指标,分层,锁

极客大学架构师训练营

架构师训练营 1 期 -- 第七周笔记

曾彪彪

极客大学架构师训练营

架构师系列之4 手写单例

桃花原记

架构师训练营1期 第七周作业

谭明华

极客大学架构师训练营

C语言重点——指针篇(一文让你完全搞懂指针)| 从内存理解指针 | 指针完全解析

公众号@编程指北

c++ 编程 后端 指针 C语言

第七周作业(作业二)

Geek_83908e

极客大学架构师训练营

第7周课后作业

happy

第七周学习性能优化1 总结

三板斧

架构师训练营 作业3

Arthur

极客大学架构师训练营

极客大学架构师课程-第三周-作业

井中人

极客大学架构师训练营

作业-第3周总结

arcyao

架构师训练营1期 第七周总结

谭明华

第三周学习总结

Griffenliu

区块链互联互通成为焦点

CECBC

区块链

Week3 作业

lggl

作业

多个区块链细分标准发布

CECBC

区块链 贸易

甲方日常 46

句子

工作 随笔杂谈 日常

iOS性能优化 — 四、内存泄露检测

iOSer

ios 性能优化 编程语言 ios开发 内存泄露检测

架构师训练营 Week7 - 课后作业

压测 极客大学架构师训练营 LoadRunner

2020.11.02-2020.11.08 学习总结

icydolphin

极客大学架构师训练营

Week3- 面向对象的设计模式(作业二)

shuyaxx

架构师训练营 1 期 -- 第七周作业

曾彪彪

极客大学架构师训练营

目标检测之RetinaNet

Dreamer

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