iOS無障礙適配西瓜視頻Voice?Over實(shí)踐示例
為了解決老年人、殘疾人等群體在使用互聯(lián)網(wǎng)等智能技術(shù)時遇到的困難,自 2021 年春季開始,西瓜視頻開展了無障礙與適老化改造專項行動。陸續(xù)完成了無障礙影院、色弱模式、護(hù)眼模式、大字號模式、外掛字幕等多個改造需求,充分滿足了視力障礙、聽力障礙以及老年人等特殊群體的需求。
一、Voice Over 簡介
Voice Over 旁白是蘋果手機(jī)自帶的工具。它能讓人們在不看屏幕的情況下了解頁面內(nèi)容和信息。盲人用戶在使用 iOS 設(shè)備時依賴 Voice Over 提供聽覺反饋。蘋果在自研的各類系統(tǒng)中均實(shí)現(xiàn)了 Voice Over 功能,如 OS X,iOS,watchOS 等等。透過 Voice Over 視障用戶可以在不同設(shè)備上獲得相同的體驗(yàn)。
使用旁白來訪問西瓜視頻的用戶有很多,“盲人小馬哥”就是其中的一位,感興趣的同學(xué)可以通過觀看他的視頻進(jìn)一步了解旁白。
二、Voice Over 使用指南
本節(jié)介紹了 Voice Over 開發(fā)者通常需要配置的開發(fā)環(huán)境。并以西瓜視頻為例,演示了 Voice Over 的基本操作。
Voice Over 開發(fā)環(huán)境配置
為了測試的方便,建議開發(fā)者可以將輔助功能快捷鍵設(shè)置成 VoiceOver 的切換,只需要連按三次右側(cè)開關(guān)鍵就能開啟/關(guān)閉 VoiceOver。
下方路徑中的 “通用” 適用于低版本系統(tǒng),高版本系統(tǒng)通過設(shè)置-> “輔助功能” 即可找到旁白
開啟/關(guān)閉 Voice Over(旁白)
設(shè)置 -> “通用” -> “輔助功能” -> “VoiceOver”(旁白)
設(shè)置連按三次右側(cè)開關(guān)鍵開啟/關(guān)閉 Voice Over(旁白) (開啟后可以便捷的打開/關(guān)閉旁白)
設(shè)置 -> “通用” -> “輔助功能” ->“輔助功能快捷鍵”,勾選 Voice Over 功能。
開啟 Voice Over+字幕面板 (開啟后可以便捷的查看旁白的全部朗讀文案)
設(shè)置 -> “通用” -> “輔助功能” ->“VoiceOver”->“字幕面板”
Voice Over 基本使用 —— 以西瓜為例
Voice Over 常用手勢詳解
這里主要例舉出 iOS 系統(tǒng)和西瓜視頻中最常用的手勢,完整操作可以參照蘋果官方文檔
https://support.apple.com/zh-cn/guide/iphone/iph3e2e3a6d/15.0/ios/15.0
入門手勢
- 使用手勢進(jìn)行元素篩選
輕點(diǎn)或觸摸項目——選擇并朗讀項目
向右輕掃——選擇下一項
向左輕掃——選擇上一項
三指向某個方向滑動——翻頁操作,可以使 UIScrollView(包括 TableView、CollectionView)向某個方向翻動一頁
- 使用手勢響應(yīng)元素事件
輕點(diǎn)兩下——響應(yīng)當(dāng)前元素的事件
輕點(diǎn)三下——雙擊當(dāng)前所選元素
雙指輕點(diǎn)兩下——響應(yīng)開發(fā)者定義的快捷事件 (如播放視頻、暫停視頻等)
雙指左右滑動(快速來回移動雙指三次,形成“Z”字形)——關(guān)閉彈窗或返回到上一級頁面
雙指輕點(diǎn)兩下并按住——用戶自定義元素名稱
進(jìn)階手勢
- 使用手勢快速篩選元素
四指輕點(diǎn)屏幕頂部附近——選擇屏幕上的第一項
四指輕點(diǎn)屏幕底部附近——選擇屏幕上的最后一項
- 使用“旁白”轉(zhuǎn)子
您可以使用轉(zhuǎn)子來更改“旁白”設(shè)置(如語速、遍歷方法等),在屏幕上從一個項目跳到下一個項目,以及選擇特殊輸入方法(如“盲文屏幕輸入”或“手寫”)等。有關(guān)詳細(xì)信息,請參閱在 iPhone 上使用轉(zhuǎn)子控制“旁白”
https://support.apple.com/zh-cn/guide/iphone/iph3e2e3a6d/15.0/ios/15.0
通過以下手勢來使用轉(zhuǎn)子。
雙指轉(zhuǎn)動——選取轉(zhuǎn)子設(shè)置
向上輕掃——移到上一項或調(diào)高(取決于轉(zhuǎn)子設(shè)置)
向下輕掃——移到下一項或調(diào)低(取決于轉(zhuǎn)子設(shè)置)
三、快速適配 Voice Over / 無障礙
想讓 App 達(dá)到無障礙基本可用并非難事,通過設(shè)置無障礙焦點(diǎn)、設(shè)置無障礙文案、調(diào)整焦點(diǎn)順序三步可以完成絕大多數(shù)的無障礙適配工作。本節(jié)對以上三步適配進(jìn)行了快速入門的介紹,并將西瓜首頁作為實(shí)戰(zhàn)案例為大家講解。
設(shè)置無障礙焦點(diǎn)
焦點(diǎn)是視力障礙用戶訪問應(yīng)用的唯一途徑,Voice Over 開啟時,如果一個元素沒有被設(shè)置為焦點(diǎn),那么該元素在屏幕中將不可被訪問。用戶可以通過在屏幕上移動焦點(diǎn)來“瀏覽”內(nèi)容。正確的焦點(diǎn)標(biāo)注和焦點(diǎn)順序能夠讓讀屏軟件用戶獲得更好的體驗(yàn)。
打開旁白后,系統(tǒng)會使用黑色框體框選當(dāng)前的焦點(diǎn)。通過輕觸某個位置 或 單指左右輕掃即可切換焦點(diǎn)。
- 哪些場景需要焦點(diǎn):
除裝飾性組件以外的功能性組件都需要焦點(diǎn),如標(biāo)題、作者頭像、點(diǎn)贊、收藏、評論、更多等。
- 哪些場景需要合并焦點(diǎn):
功能相同且距離近的焦點(diǎn)需要合并。如作者名稱、作者頭像(功能都是跳轉(zhuǎn)個人主頁,且距離近)。
需要高效篩選信息的場景需要合并,保留合并焦點(diǎn)的主功能,其余功能添加到轉(zhuǎn)子中,如 Feed。具體參照各業(yè)務(wù)方設(shè)計。
- 如何設(shè)置無障礙焦點(diǎn):
針對絕大多數(shù)情況,我們可以利用以下的幾個屬性來調(diào)整焦點(diǎn)。
isAccessibilityElement
:使用該屬性可以調(diào)整單個元素的無障礙可見性。對于大多數(shù) UI 基本元素,當(dāng)父控件為無障礙元素時,子控件將無法獲焦。
accessibilityElementsHidden
:使用該屬性可以調(diào)整單個元素及其 subviews的無障礙可見性,一般用于屏蔽整個組件。
accessibilityViewIsModal
:使用該屬性可以使該元素在同級 view中保持唯一可見性。常見場景見焦點(diǎn)被覆蓋時仍然可以被訪問。
設(shè)置無障礙文案
好的無障礙文案可以讓用戶清晰的了解到當(dāng)前焦點(diǎn)的目的,一般來說我們可以將元素按照按鈕、輸入框、搜索框等來劃分,從而進(jìn)行標(biāo)注。
當(dāng)我們參照“開發(fā)環(huán)境配置”配置好字幕后,旁白朗讀的文案將顯示在屏幕的底部。
- 無障礙文案應(yīng)該包含什么:
無障礙文案需要能準(zhǔn)確描述一個焦點(diǎn)的功能及當(dāng)前的狀態(tài) (如 已選定、點(diǎn)贊、標(biāo)簽欄)。如果一個焦點(diǎn)包含多個不同的內(nèi)容,應(yīng)當(dāng)按照信息優(yōu)先級,將該焦點(diǎn)內(nèi)全部肉眼可見信息全部朗讀。
- 如何配置無障礙文案:
從代碼層面來看,我們可以通過以下的幾個屬性來設(shè)置無障礙文案。
accessibilityLabel
:一般來說,任意元素都需要設(shè)置 Label,Label 應(yīng)當(dāng)為短語 如:點(diǎn)贊、收藏;
accessibilityValue
:(可選)用于經(jīng)常變化的標(biāo)簽數(shù)據(jù)類文案,例如 視頻的點(diǎn)贊按鈕的具體數(shù)值 (共 xxx 人);
accessibilityTraits
:當(dāng)元素作為一個無障礙焦點(diǎn)時,我們需要描述該焦點(diǎn)的類別,如按鈕、已選中等。此時需要使用 Traits 對元素進(jìn)行標(biāo)記;
accessibilityHint
:(可選)當(dāng)元素標(biāo)簽無法明確指出動作結(jié)果的時候,應(yīng)該給出一個提示;
accessibilityFrame
:當(dāng)元素的焦點(diǎn)過小,需要手動調(diào)整焦點(diǎn)到較大值的時候,可以使用 Frame
VoiceOver 會把這幾個屬性連接起來,一般情況朗讀順序?yàn)?code>accessibilityLabel→accessibilityValue
→accessibilityTraits
→accessibilityHint
。
特例:accessibilitytraits
中包含UIAccessibilityTraitSelected
則會在最前方朗讀“已選定”。
調(diào)整焦點(diǎn)順序
焦點(diǎn)順序應(yīng)該遵循 從左往右 & 從上到下。正常情況下,焦點(diǎn)的順序與 SubViews 的順序一致,我們無需手動置頂焦點(diǎn)順序。如果焦點(diǎn)順序出現(xiàn)問題,我們可以利用 UIAccessibilityContainer 來調(diào)整屏幕中焦點(diǎn)的順序。
accessibilityElements
:通過該屬性,我們可以指定一個元素包含的所有無障礙子元素。
UITableViewCell 中重設(shè)需要格外謹(jǐn)慎,可能會出現(xiàn)焦點(diǎn)循環(huán)問題。
以下圖為例,如果 C、D、E 是無障礙可視元素,通過如下設(shè)置我們就能使無障礙元素按照 D、E、C 的順序來排列。
A.accessibilityElements = @[B, C] B.accessibilityElements = @[D, E]
西瓜首頁適配實(shí)戰(zhàn)
下面以西瓜首頁為示例,為大家演示無障礙的基礎(chǔ)適配。
以西瓜首頁為例,自上而下我們主要有五個區(qū)域需要設(shè)置焦點(diǎn)。分別是 搜索欄、頻道欄 & 頻道編輯器、作者動態(tài)欄 (Story)、視頻卡片 (卡片為一個焦點(diǎn),用戶通過轉(zhuǎn)子進(jìn)行其他操作)、底部 Tab 選擇器。下面針對每個部分進(jìn)行無障礙適配的解釋。
搜索欄
searchBox.isAccessibilityElement = YES; searchBox.accessibilityLabel = @"搜索框"; searchBox.accessibilityValue = @"熱搜詞1,第一座4萬億GDP的城市。熱搜詞2,南昌至臺灣專列開通"; searchBox.accessibilityTraits = UIAccessibilityTraitSearchField;
頻道欄 & 頻道編輯器
/// 頻道欄的無障礙適配 categoryCell.isAccessibilityElement = YES; categoryCell.accessibilityLabel = @"推薦頻道"; categoryCell.accessibilityVaule = @"熱搜詞1,第一座4萬億GDP的城市。熱搜詞2,南昌至臺灣專列開通"; categoryCell.accessibilityHint = @"輕點(diǎn)兩下切換首頁頻道"; /// 未選中時 categoryCell.accessibilityTraits = UIAccessibilityTraitTabBar; /// 已選中時 categoryCell.accessibilityTraits = UIAccessibilityTraitTabBar|UIAccessibilityTraitSelected; /// 頻道編輯器的無障礙適配 // 如果面板是以addSubview的形式添加到界面上時,需要屏蔽底層元素的訪問 @implementation categoryEditViewController - (void)viewDidAppear { categoryEditView.accessibilityViewIsModal = YES; /// 使用戶焦點(diǎn)移動到頻道編輯面板上。 UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, categoryEditView); } - (void)viewDidDisAppear { categoryEditView.accessibilityViewIsModal = NO; } @end
作者動態(tài)欄
storyCell.isAccessibilityElement = YES; storyCell.accessibilityLabel = isLive ? @"入江閃閃,正在直播" : @"入江閃閃"; storyCell.accessibilityHint = isLive ? @"輕點(diǎn)兩下進(jìn)入作者直播觀看視頻" : @"輕點(diǎn)兩下進(jìn)入作者視頻列表播放視頻"; @implementation storyCell // TableView與CollectionView嵌套時,cell可能會出現(xiàn)無法自然滾動的問題。 - (void)accessibilityElementDidBecomeFocused { [self.collectionView scrollToIndexPath:self.indexPath]; } @end
視頻列表
videoCell.isAccessibilityElement = YES videoCell.accessibilityLabel = [視頻標(biāo)題、作者名稱、點(diǎn)贊數(shù)、收藏數(shù)、評論數(shù)等] videoCell.accessibilityHint = @"輕點(diǎn)兩下進(jìn)入詳情頁播放視頻,上下輕掃使用轉(zhuǎn)子訪問更多功能" UIAccessibilityCustomAction * action1 = [[UIAccessibilityCustomAction alloc] initWithName:@"點(diǎn)贊" target:self selector:@selector(action1)]; UIAccessibilityCustomAction * action2 = [[UIAccessibilityCustomAction alloc] initWithName:@"收藏" target:self selector:@selector(action2)]; UIAccessibilityCustomAction * action3 = [[UIAccessibilityCustomAction alloc] initWithName:@"更多" target:self selector:@selector(action3)]; videoCell.accessibilityCustomActions = @[action1,action2,action3];
四、Voice Over 相關(guān)協(xié)議介紹
UIAccessibility 無障礙標(biāo)簽標(biāo)注
@interface NSObject (UIAccessibility) /// 標(biāo)記一個元素是否是無障礙元素 @property (nonatomic) BOOL isAccessibilityElement; /// 標(biāo)記一個元素的無障礙元素的簡短描述 如 (點(diǎn)贊、收藏) @property (nullable, nonatomic, copy) NSString *accessibilityLabel; /// (可選)標(biāo)記一個元素的無障礙元素的詳細(xì)描述 如 (輕點(diǎn)兩下與xxx人一起點(diǎn)贊,輕點(diǎn)兩下將視頻添加到收藏列表) @property (nullable, nonatomic, copy) NSString *accessibilityHint; /// (可選)標(biāo)記一個元素的無障礙元素的具體值,如50%等 @property (nullable, nonatomic, copy) NSString *accessibilityValue; /// (可選)標(biāo)記一個元素的無障礙特征 如(按鈕、標(biāo)簽夾等) @property (nonatomic) UIAccessibilityTraits accessibilityTraits; /// (可選)自定義一個元素的無障礙模式下的焦點(diǎn)大小 @property (nonatomic) CGRect accessibilityFrame; @end
UIAccessibilityAction 無障礙手勢響應(yīng)
@interface NSObject (UIAccessibilityAction) /// 自定義無障礙事件,可以使點(diǎn)擊事件與普通用戶隔離。 - (BOOL)accessibilityActivate API_AVAILABLE(ios(7.0)); /// 當(dāng)元素被定義為可變元素時,可以實(shí)現(xiàn)下面的方法。如音量、亮度調(diào)節(jié)器。 - (void)accessibilityIncrement API_AVAILABLE(ios(4.0)); - (void)accessibilityDecrement API_AVAILABLE(ios(4.0)); - (BOOL)accessibilityScroll:(UIAccessibilityScrollDirection)direction API_AVAILABLE(ios(4.2)); /// 通常浮窗或頁面需要實(shí)現(xiàn)該方法,實(shí)現(xiàn)該方法后用戶可以使用“Z”字形手勢退出頁面 - (BOOL)accessibilityPerformEscape API_AVAILABLE(ios(5.0)); /// 該方法可以接收到用戶的雙指雙擊事件??梢杂糜趶棾龈嗝姘?or 定義一些重要操作如 暫停。 - (BOOL)accessibilityPerformMagicTap API_AVAILABLE(ios(6.0)); /// 轉(zhuǎn)子的核心方法,給accessibilityCustomActions賦值后可以上下輕掃訪問轉(zhuǎn)子 @property (nullable, nonatomic, strong) NSArray <UIAccessibilityCustomAction *> *accessibilityCustomActions API_AVAILABLE(ios(8.0)); @end
UIAccessibilityFocus 無障礙焦點(diǎn)響應(yīng)
@interface NSObject (UIAccessibilityFocus) /// 焦點(diǎn)響應(yīng)事件,可以捕獲元素是否成為了焦點(diǎn)。通常重寫這兩個方法。 - (void)accessibilityElementDidBecomeFocused API_AVAILABLE(ios(4.0)); - (void)accessibilityElementDidLoseFocus API_AVAILABLE(ios(4.0)); /// 可以判斷該元素是否被聚焦,通常不要處理該方法。 - (BOOL)accessibilityElementIsFocused API_AVAILABLE(ios(4.0)); @end
UIAccessibilityContainer 無障礙自定義焦點(diǎn)
@interface NSObject (UIAccessibilityContainer) /// 返回當(dāng)前容器無障礙元素的總數(shù) - (NSInteger)accessibilityElementCount NS_SWIFT_UI_ACTOR; /// 返回對應(yīng)index的元素 /// 需要保證返回的是真實(shí)存在的實(shí)例(不能為alloc出來的) - (nullable id)accessibilityElementAtIndex:(NSInteger)index NS_SWIFT_UI_ACTOR; /// 返回對應(yīng)元素的index - (NSInteger)indexOfAccessibilityElement:(id)element NS_SWIFT_UI_ACTOR; ??如果使用上面的三個方法,一般需要同時全部實(shí)現(xiàn)。 ??如果實(shí)現(xiàn)了上面的三個方法,那么就不要再手動設(shè)置accessibilityElements /// 容器的無障礙元素List,設(shè)置后頁面無障礙元素范圍將會被限制在List內(nèi),順序與List內(nèi)元素順序相同。 @property (nullable, nonatomic, strong) NSArray *accessibilityElements API_AVAILABLE(ios(8.0)) NS_SWIFT_UI_ACTOR; /// default == UIAccessibilityContainerTypeNone,絕大多數(shù)情況保持None即可。如果手動設(shè)置Type則需要實(shí)現(xiàn)對于Type的指定協(xié)議。 @property (nonatomic) UIAccessibilityContainerType accessibilityContainerType API_AVAILABLE(ios(11.0)) NS_SWIFT_UI_ACTOR; @end
五、常見問題與解決方案
該部分根據(jù)西瓜真實(shí)的業(yè)務(wù)實(shí)踐,列舉了數(shù)個常見無障礙問題的修復(fù)方案。例如:焦點(diǎn)目的不明確、焦點(diǎn)亂跳問題、嵌套容器 ScrollView 無法跟隨滾動等。
焦點(diǎn)缺失/焦點(diǎn)冗余
焦點(diǎn)缺失是無障礙 Bug 中最基礎(chǔ)但最嚴(yán)重的問題。極端情況情況下會產(chǎn)生致命的阻塞性的 Bug(如返回按鈕缺失焦點(diǎn))。通常而言產(chǎn)品上一些按鈕、鏈接、勾選框、圖片、編輯框等需要焦點(diǎn)方便用戶交互。
此外焦點(diǎn)冗余也會嚴(yán)重影響用戶的使用體驗(yàn),一些裝飾性元素焦點(diǎn)冗余后,用戶的信息篩選效率會嚴(yán)重降低。通常而言,用戶點(diǎn)擊后無明確響應(yīng)事件的組件不應(yīng)該成為焦點(diǎn)。
「解決方法」:一般情況下,系統(tǒng)會自動給標(biāo)準(zhǔn)控件 UIButton 等交互控件添加焦點(diǎn),其他自定義控件需要手動添加/更改。一般情況下手動指定屬性isAccessibilityElement
為 YES 或者 NO 可解決該問題。
self.isAccessibilityElement = YES; self.accessibilityLabel = @"點(diǎn)贊"; // 通常焦點(diǎn)描述也會缺失,需要一并補(bǔ)充。 /// 對于一些自定義的UI控件,也可以重寫上述兩個對象的Get方法。 - (NSString *)accessibilityLabel { return @"點(diǎn)贊"; } - (BOOL) isAccessibilityElement { return YES; }
焦點(diǎn)過細(xì)/焦點(diǎn)合并
焦點(diǎn)合并指的是有相同目的、相同操作的,或具有組合意義的組合視圖,焦點(diǎn)沒有合并的情況,問題描述為“合并焦點(diǎn)”。例如,好友列表中的好友頭像和昵稱應(yīng)合并為一個焦點(diǎn),二者功能都一樣,都是跳轉(zhuǎn)到個人資料界面。
「解決方法」:在需要合并焦點(diǎn)的 superView 處將 isAccessibilityElement 設(shè)置為 YES。
self.isAccessibilityElement = YES;
焦點(diǎn)信息錯誤 (目的不明確,信息冗余等)
焦點(diǎn)目的不明確是指頁面中的焦點(diǎn)僅朗讀出基本文案,但是未朗讀該控件的類型(按鈕、標(biāo)簽欄、鏈接等),或者未朗讀該焦點(diǎn)響應(yīng)后會發(fā)生的事件(輕點(diǎn)兩下進(jìn)入詳情頁播放視頻等)。
「解決方法」:參照產(chǎn)品的無障礙標(biāo)注規(guī)范。調(diào)整問題焦點(diǎn)的 accessibilityLabel、accessibilityTraits、accessibilityHint 等字段,從而使焦點(diǎn)信息朗讀準(zhǔn)確。
/// Button // 點(diǎn)贊按鈕未被選中時 self.accessibilityTraits = UIAccessibilityTraitButton; self.accessibilityHint = @"輕點(diǎn)兩下與xxx人一同點(diǎn)贊"; // 點(diǎn)贊按鈕被選中時 self.accessibilityTraits = UIAccessibilityTraitButton|UIAccessibilityTraitSelected; self.accessibilityHint = @"輕點(diǎn)兩下取消點(diǎn)贊"; ///TabBar(包括頂Tab和底Tab) // 當(dāng)對象為TabBar self.accessibilityTraits = UIAccessibilityTraitTabBar // 被選中的TabBar self.accessibilityTraits = UIAccessibilityTraitTabBar|UIAccessibilityTraitSelected;
焦點(diǎn)停留不當(dāng)
頁面刷新后跑焦點(diǎn)、對視圖或控件進(jìn)行操作后跑焦點(diǎn),打開新界面焦點(diǎn)停留的位置不適當(dāng),問題描述為“焦點(diǎn)停留不當(dāng)”。例如進(jìn)入一些頁面后,焦點(diǎn)默認(rèn)停留在原位置,或者停留在新頁面的返回按鈕。
「解決方法」:在進(jìn)入界面時將 VoiceOver 焦點(diǎn)定位到特定控件??梢允褂?code>UIAccessibilityPostNotification發(fā)送通知給特定控件,改變 voiceOver 焦點(diǎn)。
@implementation MyViewController - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, self.myFirstElement); } @end
焦點(diǎn)順序錯誤問題
焦點(diǎn)順序不符合邏輯順序時,通常描述為:“焦點(diǎn)順序不符合邏輯順序”;焦點(diǎn)順序不符合視覺順序時,描述為“焦點(diǎn)順序不符合視覺順序”。
「解決方法」:手動設(shè)置 accessibilityElements。極端場景下可以主動實(shí)現(xiàn) UIAccessibilityContainer 協(xié)議。
/// 普通場景. 切勿在TableView的Cell中使用 self.accessibilityElements = @[View1,View2,View3]; /// 復(fù)雜場景,務(wù)必將三個方法都實(shí)現(xiàn),否則容易出現(xiàn)意料之外的問題 - (NSInteger)accessibilityElementCount { return 3; } - (nullable id)accessibilityElementAtIndex:(NSInteger)index { return Views[index]; } - (NSInteger)indexOfAccessibilityElement:(id)element { return [Views indexOfObject:element]; }
焦點(diǎn)選中時亂跳問題
該問題主要發(fā)生在 CollectionView 上,一般現(xiàn)象為調(diào)整一個 Cell 的選中態(tài)并 reloadData,焦點(diǎn)會先轉(zhuǎn)移到一個隨機(jī)的位置(一般是選中 Cell 的后一個),而后再跳回正確的位置。
「解決方法」:慎用 UICollectionView、UITableView 的 reloadData。當(dāng)需要刷新 Cell 的選中狀態(tài)時,盡量自己實(shí)現(xiàn)一個 updateVisibleCell。reloadData 時會導(dǎo)致 Cell 隨機(jī)復(fù)用,最終產(chǎn)生焦點(diǎn)亂跳的異常。
? [self reloadData]; ? [self updateVisibleCells]; - (void)updateVisibleCells { NSArray<UICollectionViewCell *> *visibleCells = self.collectionView.visibleCells; [visibleCells enumerateObjectsUsingBlock:^(UICollectionViewCell * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { // Todo something }]; }
浮窗問題 / 焦點(diǎn)被覆蓋時仍可訪問
在西瓜視頻中,浮窗有多種不同的存在形式,如 XIGAlert(隱私彈窗等)、XIGToast(網(wǎng)絡(luò)異常等)、半屏浮窗(鍵盤、清晰度面板、倍速面板等)。在彈窗出現(xiàn)時,用戶可以通過左右滑動切換焦點(diǎn)至不可視的視圖。這些視圖產(chǎn)生的相關(guān)事件可能會使程序崩潰,發(fā)生一些意料之外的事情。
「解決方法」:一般做法為讓底層控件元素失去焦點(diǎn)來達(dá)到屏蔽底層元素的效果,將灰色變暗區(qū)域設(shè)為單個大焦點(diǎn),標(biāo)簽設(shè)為 “關(guān)閉” 或 “收起” 等提示,雙擊可關(guān)閉浮層。彈窗或彈層時,自動使上層容器的第一控件(如標(biāo)題或通知內(nèi)容)獲取焦點(diǎn),視障用戶無須二次切換焦點(diǎn),更符合視障用戶使用體驗(yàn),更加體現(xiàn)人性化。
self.accessibilityViewIsModal = YES
對蒙層設(shè)置屬性,會使蒙層的同級 view不響應(yīng) VoiceOver,而蒙層的子 view 可響應(yīng)。如下圖所示,如果希望 E 可以被訪問,CD 不可被訪問,此時需要設(shè)置 B 的accessibilityViewIsModal
為 YES。
嵌套容器 ScrollView 無法跟隨滾動問題
在 UICollectionView 中,嵌套一個 UIScrollView 或者 UITableView,焦點(diǎn)在 TableView、ScrollView 中滑動時,不會發(fā)生自動滾動,從而導(dǎo)致頁面發(fā)生白屏等現(xiàn)象。
「解決方法」:使用 accessibilityActivate,在焦點(diǎn)聚焦到一個 Cell 上的時候,手動調(diào)用
scrollToRowAtIndexPath: atScrollPosition: animated:
如果一個 Cell 中包含多個功能,Cell 還需要進(jìn)行轉(zhuǎn)子適配。
- (BOOL)accessibilityElementDidBecomeFocused { [self.tableview scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionNone animated:NO]; return YES; }
橫滑拖拽問題(手勢替代問題)
在應(yīng)用中有許多場景有橫滑手勢,如橫滑刪除,橫滑編輯等。此類事件在 Voice Over 開啟時無法被響應(yīng)。故需要通過一些其他手段使用戶能夠訪問到橫滑的功能。
「解決方法」:使用轉(zhuǎn)子對功能進(jìn)行改造。
UIAccessibilityCustomAction * action1 = [[UIAccessibilityCustomAction alloc] initWithName:@"進(jìn)入詳情頁" target:self selector:@selector(action1)]; UIAccessibilityCustomAction * action2 = [[UIAccessibilityCustomAction alloc] initWithName:@"刪除該視頻" target:self selector:@selector(action2)]; UIAccessibilityCustomAction * action3 = [[UIAccessibilityCustomAction alloc] initWithName:@"隱藏該視頻" target:self selector:@selector(action3)]; self.accessibilityCustomActions = @[action1,action2,action3];
以上就是iOS無障礙適配西瓜視頻Voice Over實(shí)踐示例的詳細(xì)內(nèi)容,更多關(guān)于iOS適配Voice Over的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
iOS開發(fā)中以application/json上傳文件實(shí)例詳解
在和sever后臺交互的過程中、有時候、他們需要我們iOS開發(fā)者以“application/json”形式上傳,具體實(shí)例代碼大家參考下本文2017-07-07iphone的safari瀏覽器中實(shí)現(xiàn)全屏瀏覽的方法
這篇文章主要介紹了iphone的safari瀏覽器中實(shí)現(xiàn)全屏瀏覽的方法,同時介紹了Add to Home Screen功能的實(shí)現(xiàn)方法,需要的朋友可以參考下2014-06-06詳解Objective-C設(shè)計模式編程中對備忘錄模式的運(yùn)用
這篇文章主要介紹了Objective-C設(shè)計模式編程中對備忘錄模式的運(yùn)用,文中結(jié)合了Cocoa框架下應(yīng)用的實(shí)例來加以講解,需要的朋友可以參考下2016-03-03iOS 原生實(shí)現(xiàn)掃描二維碼和條形碼功能限制掃描區(qū)域
這篇文章主要介紹了iOS 原生實(shí)現(xiàn)掃描二維碼和條形碼功能限制掃描區(qū)域,需要的朋友可以參考下2017-03-03iOS實(shí)現(xiàn)拖拽View跟隨手指浮動效果
這篇文章主要為大家詳細(xì)介紹了iOS實(shí)現(xiàn)拖拽View跟隨手指浮動,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-02-02