Categories
程式開發

優酷暗黑模式(八):分發場景落地(Android & iOS)


一、背景介紹

隨著Android 10與iOS 13先後支持暗黑模式,優酷客戶端在完成了架構統一和組件標準化的工作之後,分發場景的複雜業務可以基於統一的技術方案進行暗黑模式的適配。

二、業務介紹

由於優酷業務分發場景業務複雜,承載頁面眾多(二十多種),在落地暗黑模式前,我們對優酷分發場景的業務進行了梳理,大致可以分為三類:

第一類是固定入口的頁面,比如首頁、頻道、Feed流、二級頁,它們承接了分發場景的大部分業務,擁有樣式豐富的組件庫,它們的共性非常高。

優酷暗黑模式(八):分發場景落地(Android & iOS) 1

第二類是獨立業務方開發的二級頁,這些二級頁由垂直業務團隊維護。由於優酷客戶端已完成架構統一和組件標準化的工作,各個業務團隊適配暗黑模式都是基於同一套技術方案,適配就變成了一個標準化的工作。業務團隊只需按統一的方式適配即可,極大提高了開發效率。

優酷暗黑模式(八):分發場景落地(Android & iOS) 2

第三類是一些歷史遺留的一些老頁面,這些頁面沒有固定的入口,入口分散在各個頁面和各個組件, 適配暗黑模式成本相對較高。

這樣的頁面可以有兩種處理方式:

  1. 流量小,非核心的分發場景,面臨下線的業務不進行暗黑模式的適配。

  2. 有業務價值的頁面進行遷移或合併,統一用新版的二級頁承載。

優酷暗黑模式(八):分發場景落地(Android & iOS) 3

優酷暗黑模式(八):分發場景落地(Android & iOS) 4

三、暗黑適配

頁面展現分幾種狀態:轉場態, 加載態(Loading), 展現態,異常態。暗黑模式適配的主要工作是適配頁面的展現態;轉場態和加載態的生命週期雖然很短,但是不能忽略,否則很容易出現亮色-暗色頁面狀態的切換,會破壞整體的沉浸式瀏覽體驗,異常態也是因為類似原因不能忽略。

優酷暗黑模式(八):分發場景落地(Android & iOS) 5

1、頁面級別

1) 頂部/底部導航/容器

頂部導航支持換背景色;底部導航支持換圖片資源、文字顏色、背景顏色;容器支持背景色。

優酷暗黑模式(八):分發場景落地(Android & iOS) 6

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 *)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 & iOS) 7

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 * _Nullable theme) {
        // 暗黑模式下的图
        if ([identifier isEqualToString:YKNThemeIdentifierDark]) {
            return [UIImage imageNamed:@"home_feed_loading_default_d"] ;
        }
        // 浅色模式下的图
        return [UIImage imageNamed:@"home_feed_loading_default"];
    }];
}

3) 暗黑與氛圍/換膚的兼容問題

優酷分發場景支持換膚、氛圍和暗黑模式,優先級為氛圍>換膚>暗黑。所有頁面、組件都在此規則上進行適配。

a) 頁面同時存在氛圍+暗黑

電影頻道為了培養頻道用戶的心智,定義了頭部和輪播的氛圍色。

優酷暗黑模式(八):分發場景落地(Android & iOS) 8

b) 頁面整體都是氛圍

高清頻道突出高清適配的質感,將整個高清頻道頁面都定義了氛圍色。

優酷暗黑模式(八):分發場景落地(Android & iOS) 9

2、組件級別

分發場景有幾十種組件,大部分組件接入非常便捷,只需將引用的資源字段改為DesignToken即可;

1) 常規組件

這裡Android和iOS實現有些差異,需要分別說明。

a) Android

優酷暗黑模式(八):分發場景落地(Android & iOS) 10

Android為了提高性能,有些文本繪製使用了自定義View來單獨繪製文本,目的是減少View數量和減少View的measure時間,上圖的PhoneCommonTitlesWidget就是一個封裝了標題繪製的自定義View。

下面的代碼主要是說明瞭如何使用DesignToken,使用DesignToken色值有兩種方式。

第一種,通過Layout佈局文件使用包含DesignToken的Style,這種方式方式一般用於系統控件,或繼承自系統控件的簡單封裝比如YKTextView:

 

 
        @dimen/font_size_big1
        bold
        true
        false
        end
        @color/ykn_primary_info //DesignToken颜色
    

第二種,通過代碼使用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

優酷暗黑模式(八):分發場景落地(Android & iOS) 11

有些組件業務邏輯複雜、視圖的層級很深,找到相應的代碼非常耗時,我們可以使用Xcode的Debug工具、也可以使用優酷開發的一套UI檢查工具(啄木鳥),來快速適配暗黑模式。

// 标题:一级信息色Token
_titleLabel.textColor = [UIColor ykn_primaryInfo];

// 子标题:二级信息色Token
_subtitleLabel.textColor = [UIColor ykn_secondaryInfo];

// 边框:升起的一级组块背景Token
_borderView.backgroundColor = [UIColor ykn_elevatedPrimaryBackground];

2)特殊組件

優酷有些組件展示的主體是服務端下發的圖片,但是服務端暫時不支持下發視頻暗黑模式的圖片。針對這種組件就需要有個降級策略,盡量保證暗黑模式的整體顯示效果,這種屬於特例情況要根據自己的業務特性來定義降級模式。

優酷暗黑模式(八):分發場景落地(Android & iOS) 12

下面是一個具體的樣例。

四、遇到的問題

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. 對比系統原生暗黑

優酷暗黑模式(八):分發場景落地(Android & iOS) 13

五、適配效果

優酷暗黑模式(八):分發場景落地(Android & iOS) 14

六、總結

暗黑模式對於視頻類應用可以明顯提升用戶體驗,在觀感上更適合沉浸式的深度瀏覽,對於夜晚使用能有效避免亮色模式“刺眼”, 對眼睛更加舒適。因為LED屏幕在顯示黑色像素的時候並不發光,因而可以提升續航時間,看劇更持久。

用戶主路徑涉及到的頁面,彈窗,甚至圖片默認打底圖,Loading圖,頁面加載出來前的骨架圖盡量都適配暗黑模式。由於人眼對由暗到亮比由亮到暗更敏感(例如: 黑夜中突然的車燈會晃得睜不眼睛),主業務場景的暗黑模式盡量避免亮色模式的UI元素帶來視覺反差,破壞用戶沉浸式瀏覽觀看體驗。

對於Android而言,暗黑模式在系統級的支持是從Android 10開始,目前Android 10的手機還沒有大規模的系統升級。在開發中我們可以通過代碼強制打開暗黑模式,方便進行開發。產品上也可以考慮在客戶端的設置項中增加“強制暗黑模式”的開關,使得低於Android 10版本的手機也可以使用暗黑模式。

作者簡介

叔平,阿里文娛無線高級開發工程師。

相關閱讀

優酷暗黑模式(一):是什麼、為什麼、如何落地?

優酷暗黑模式(二):如何建立設計語言標準化管理體系

優酷暗黑模式(三):暗黑模式設計指南

優酷暗黑模式(四):設計標準化的技術實現

優酷暗黑模式(五):暗黑模式的技術實現策略

優酷暗黑模式(六):暗黑模式的技術支撐 iOS

優酷暗黑模式(七):暗黑模式的技術支撐 Weex & H5