iOS無障礙適配西瓜視頻Voice?Over實(shí)踐示例
為了解決老年人、殘疾人等群體在使用互聯(lián)網(wǎng)等智能技術(shù)時(shí)遇到的困難,自 2021 年春季開始,西瓜視頻開展了無障礙與適老化改造專項(xiàng)行動(dòng)。陸續(xù)完成了無障礙影院、色弱模式、護(hù)眼模式、大字號(hào)模式、外掛字幕等多個(gè)改造需求,充分滿足了視力障礙、聽力障礙以及老年人等特殊群體的需求。
一、Voice Over 簡介
Voice Over 旁白是蘋果手機(jī)自帶的工具。它能讓人們?cè)诓豢雌聊坏那闆r下了解頁面內(nèi)容和信息。盲人用戶在使用 iOS 設(shè)備時(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 常用手勢(shì)詳解
這里主要例舉出 iOS 系統(tǒng)和西瓜視頻中最常用的手勢(shì),完整操作可以參照蘋果官方文檔
https://support.apple.com/zh-cn/guide/iphone/iph3e2e3a6d/15.0/ios/15.0
入門手勢(shì)
- 使用手勢(shì)進(jìn)行元素篩選
輕點(diǎn)或觸摸項(xiàng)目——選擇并朗讀項(xiàng)目
向右輕掃——選擇下一項(xiàng)
向左輕掃——選擇上一項(xiàng)
三指向某個(gè)方向滑動(dòng)——翻頁操作,可以使 UIScrollView(包括 TableView、CollectionView)向某個(gè)方向翻動(dòng)一頁
- 使用手勢(shì)響應(yīng)元素事件
輕點(diǎn)兩下——響應(yīng)當(dāng)前元素的事件
輕點(diǎn)三下——雙擊當(dāng)前所選元素
雙指輕點(diǎn)兩下——響應(yīng)開發(fā)者定義的快捷事件 (如播放視頻、暫停視頻等)
雙指左右滑動(dòng)(快速來回移動(dòng)雙指三次,形成“Z”字形)——關(guān)閉彈窗或返回到上一級(jí)頁面
雙指輕點(diǎn)兩下并按住——用戶自定義元素名稱
進(jìn)階手勢(shì)
- 使用手勢(shì)快速篩選元素
四指輕點(diǎn)屏幕頂部附近——選擇屏幕上的第一項(xiàng)
四指輕點(diǎn)屏幕底部附近——選擇屏幕上的最后一項(xiàng)
- 使用“旁白”轉(zhuǎn)子
您可以使用轉(zhuǎn)子來更改“旁白”設(shè)置(如語速、遍歷方法等),在屏幕上從一個(gè)項(xiàng)目跳到下一個(gè)項(xiàng)目,以及選擇特殊輸入方法(如“盲文屏幕輸入”或“手寫”)等。有關(guān)詳細(xì)信息,請(qǐng)參閱在 iPhone 上使用轉(zhuǎn)子控制“旁白”
https://support.apple.com/zh-cn/guide/iphone/iph3e2e3a6d/15.0/ios/15.0
通過以下手勢(shì)來使用轉(zhuǎn)子。
雙指轉(zhuǎn)動(dòng)——選取轉(zhuǎn)子設(shè)置
向上輕掃——移到上一項(xiàng)或調(diào)高(取決于轉(zhuǎn)子設(shè)置)
向下輕掃——移到下一項(xiàng)或調(diào)低(取決于轉(zhuǎn)子設(shè)置)
三、快速適配 Voice Over / 無障礙
想讓 App 達(dá)到無障礙基本可用并非難事,通過設(shè)置無障礙焦點(diǎn)、設(shè)置無障礙文案、調(diào)整焦點(diǎn)順序三步可以完成絕大多數(shù)的無障礙適配工作。本節(jié)對(duì)以上三步適配進(jìn)行了快速入門的介紹,并將西瓜首頁作為實(shí)戰(zhàn)案例為大家講解。
設(shè)置無障礙焦點(diǎn)
焦點(diǎn)是視力障礙用戶訪問應(yīng)用的唯一途徑,Voice Over 開啟時(shí),如果一個(gè)元素沒有被設(shè)置為焦點(diǎn),那么該元素在屏幕中將不可被訪問。用戶可以通過在屏幕上移動(dòng)焦點(diǎn)來“瀏覽”內(nèi)容。正確的焦點(diǎn)標(biāo)注和焦點(diǎn)順序能夠讓讀屏軟件用戶獲得更好的體驗(yàn)。

打開旁白后,系統(tǒng)會(huì)使用黑色框體框選當(dāng)前的焦點(diǎn)。通過輕觸某個(gè)位置 或 單指左右輕掃即可切換焦點(diǎn)。
- 哪些場景需要焦點(diǎn):
除裝飾性組件以外的功能性組件都需要焦點(diǎn),如標(biāo)題、作者頭像、點(diǎn)贊、收藏、評(píng)論、更多等。
- 哪些場景需要合并焦點(diǎn):
功能相同且距離近的焦點(diǎn)需要合并。如作者名稱、作者頭像(功能都是跳轉(zhuǎn)個(gè)人主頁,且距離近)。
需要高效篩選信息的場景需要合并,保留合并焦點(diǎn)的主功能,其余功能添加到轉(zhuǎn)子中,如 Feed。具體參照各業(yè)務(wù)方設(shè)計(jì)。
- 如何設(shè)置無障礙焦點(diǎn):
針對(duì)絕大多數(shù)情況,我們可以利用以下的幾個(gè)屬性來調(diào)整焦點(diǎn)。
isAccessibilityElement:使用該屬性可以調(diào)整單個(gè)元素的無障礙可見性。對(duì)于大多數(shù) UI 基本元素,當(dāng)父控件為無障礙元素時(shí),子控件將無法獲焦。
accessibilityElementsHidden:使用該屬性可以調(diào)整單個(gè)元素及其 subviews的無障礙可見性,一般用于屏蔽整個(gè)組件。
accessibilityViewIsModal:使用該屬性可以使該元素在同級(jí) view中保持唯一可見性。常見場景見焦點(diǎn)被覆蓋時(shí)仍然可以被訪問。
設(shè)置無障礙文案
好的無障礙文案可以讓用戶清晰的了解到當(dāng)前焦點(diǎn)的目的,一般來說我們可以將元素按照按鈕、輸入框、搜索框等來劃分,從而進(jìn)行標(biāo)注。
當(dāng)我們參照“開發(fā)環(huán)境配置”配置好字幕后,旁白朗讀的文案將顯示在屏幕的底部。

- 無障礙文案應(yīng)該包含什么:
無障礙文案需要能準(zhǔn)確描述一個(gè)焦點(diǎn)的功能及當(dāng)前的狀態(tài) (如 已選定、點(diǎn)贊、標(biāo)簽欄)。如果一個(gè)焦點(diǎn)包含多個(gè)不同的內(nèi)容,應(yīng)當(dāng)按照信息優(yōu)先級(jí),將該焦點(diǎn)內(nèi)全部肉眼可見信息全部朗讀。
- 如何配置無障礙文案:
從代碼層面來看,我們可以通過以下的幾個(gè)屬性來設(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)元素作為一個(gè)無障礙焦點(diǎn)時(shí),我們需要描述該焦點(diǎn)的類別,如按鈕、已選中等。此時(shí)需要使用 Traits 對(duì)元素進(jìn)行標(biāo)記;
accessibilityHint:(可選)當(dāng)元素標(biāo)簽無法明確指出動(dòng)作結(jié)果的時(shí)候,應(yīng)該給出一個(gè)提示;
accessibilityFrame:當(dāng)元素的焦點(diǎn)過小,需要手動(dòng)調(diào)整焦點(diǎn)到較大值的時(shí)候,可以使用 Frame
VoiceOver 會(huì)把這幾個(gè)屬性連接起來,一般情況朗讀順序?yàn)?code>accessibilityLabel→accessibilityValue→accessibilityTraits→accessibilityHint。
特例:accessibilitytraits中包含UIAccessibilityTraitSelected則會(huì)在最前方朗讀“已選定”。
調(diào)整焦點(diǎn)順序
焦點(diǎn)順序應(yīng)該遵循 從左往右 & 從上到下。正常情況下,焦點(diǎn)的順序與 SubViews 的順序一致,我們無需手動(dòng)置頂焦點(diǎn)順序。如果焦點(diǎn)順序出現(xiàn)問題,我們可以利用 UIAccessibilityContainer 來調(diào)整屏幕中焦點(diǎn)的順序。
accessibilityElements:通過該屬性,我們可以指定一個(gè)元素包含的所有無障礙子元素。
UITableViewCell 中重設(shè)需要格外謹(jǐn)慎,可能會(huì)出現(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ǔ)適配。

以西瓜首頁為例,自上而下我們主要有五個(gè)區(qū)域需要設(shè)置焦點(diǎn)。分別是 搜索欄、頻道欄 & 頻道編輯器、作者動(dòng)態(tài)欄 (Story)、視頻卡片 (卡片為一個(gè)焦點(diǎn),用戶通過轉(zhuǎn)子進(jìn)行其他操作)、底部 Tab 選擇器。下面針對(duì)每個(gè)部分進(jìn)行無障礙適配的解釋。
搜索欄
searchBox.isAccessibilityElement = YES; searchBox.accessibilityLabel = @"搜索框"; searchBox.accessibilityValue = @"熱搜詞1,第一座4萬億GDP的城市。熱搜詞2,南昌至臺(tái)灣專列開通"; searchBox.accessibilityTraits = UIAccessibilityTraitSearchField;
頻道欄 & 頻道編輯器
/// 頻道欄的無障礙適配
categoryCell.isAccessibilityElement = YES;
categoryCell.accessibilityLabel = @"推薦頻道";
categoryCell.accessibilityVaule = @"熱搜詞1,第一座4萬億GDP的城市。熱搜詞2,南昌至臺(tái)灣專列開通";
categoryCell.accessibilityHint = @"輕點(diǎn)兩下切換首頁頻道";
/// 未選中時(shí)
categoryCell.accessibilityTraits = UIAccessibilityTraitTabBar;
/// 已選中時(shí)
categoryCell.accessibilityTraits = UIAccessibilityTraitTabBar|UIAccessibilityTraitSelected;
/// 頻道編輯器的無障礙適配
// 如果面板是以addSubview的形式添加到界面上時(shí),需要屏蔽底層元素的訪問
@implementation categoryEditViewController
- (void)viewDidAppear {
categoryEditView.accessibilityViewIsModal = YES;
/// 使用戶焦點(diǎn)移動(dòng)到頻道編輯面板上。
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, categoryEditView);
}
- (void)viewDidDisAppear {
categoryEditView.accessibilityViewIsModal = NO;
}
@end作者動(dòng)態(tài)欄
storyCell.isAccessibilityElement = YES;
storyCell.accessibilityLabel = isLive ? @"入江閃閃,正在直播" : @"入江閃閃";
storyCell.accessibilityHint = isLive ? @"輕點(diǎn)兩下進(jìn)入作者直播觀看視頻" : @"輕點(diǎn)兩下進(jìn)入作者視頻列表播放視頻";
@implementation storyCell
// TableView與CollectionView嵌套時(shí),cell可能會(huì)出現(xiàn)無法自然滾動(dòng)的問題。
- (void)accessibilityElementDidBecomeFocused {
[self.collectionView scrollToIndexPath:self.indexPath];
}
@end視頻列表
videoCell.isAccessibilityElement = YES videoCell.accessibilityLabel = [視頻標(biāo)題、作者名稱、點(diǎn)贊數(shù)、收藏?cái)?shù)、評(píng)論數(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)記一個(gè)元素是否是無障礙元素 @property (nonatomic) BOOL isAccessibilityElement; /// 標(biāo)記一個(gè)元素的無障礙元素的簡短描述 如 (點(diǎn)贊、收藏) @property (nullable, nonatomic, copy) NSString *accessibilityLabel; /// (可選)標(biāo)記一個(gè)元素的無障礙元素的詳細(xì)描述 如 (輕點(diǎn)兩下與xxx人一起點(diǎn)贊,輕點(diǎn)兩下將視頻添加到收藏列表) @property (nullable, nonatomic, copy) NSString *accessibilityHint; /// (可選)標(biāo)記一個(gè)元素的無障礙元素的具體值,如50%等 @property (nullable, nonatomic, copy) NSString *accessibilityValue; /// (可選)標(biāo)記一個(gè)元素的無障礙特征 如(按鈕、標(biāo)簽夾等) @property (nonatomic) UIAccessibilityTraits accessibilityTraits; /// (可選)自定義一個(gè)元素的無障礙模式下的焦點(diǎn)大小 @property (nonatomic) CGRect accessibilityFrame; @end
UIAccessibilityAction 無障礙手勢(shì)響應(yīng)
@interface NSObject (UIAccessibilityAction) /// 自定義無障礙事件,可以使點(diǎn)擊事件與普通用戶隔離。 - (BOOL)accessibilityActivate API_AVAILABLE(ios(7.0)); /// 當(dāng)元素被定義為可變?cè)貢r(shí),可以實(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”字形手勢(shì)退出頁面 - (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)。通常重寫這兩個(gè)方法。 - (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; /// 返回對(duì)應(yīng)index的元素 /// 需要保證返回的是真實(shí)存在的實(shí)例(不能為alloc出來的) - (nullable id)accessibilityElementAtIndex:(NSInteger)index NS_SWIFT_UI_ACTOR; /// 返回對(duì)應(yīng)元素的index - (NSInteger)indexOfAccessibilityElement:(id)element NS_SWIFT_UI_ACTOR; ??如果使用上面的三個(gè)方法,一般需要同時(shí)全部實(shí)現(xiàn)。 ??如果實(shí)現(xiàn)了上面的三個(gè)方法,那么就不要再手動(dòng)設(shè)置accessibilityElements /// 容器的無障礙元素List,設(shè)置后頁面無障礙元素范圍將會(huì)被限制在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即可。如果手動(dòng)設(shè)置Type則需要實(shí)現(xiàn)對(duì)于Type的指定協(xié)議。 @property (nonatomic) UIAccessibilityContainerType accessibilityContainerType API_AVAILABLE(ios(11.0)) NS_SWIFT_UI_ACTOR; @end
五、常見問題與解決方案
該部分根據(jù)西瓜真實(shí)的業(yè)務(wù)實(shí)踐,列舉了數(shù)個(gè)常見無障礙問題的修復(fù)方案。例如:焦點(diǎn)目的不明確、焦點(diǎn)亂跳問題、嵌套容器 ScrollView 無法跟隨滾動(dòng)等。
焦點(diǎn)缺失/焦點(diǎn)冗余
焦點(diǎn)缺失是無障礙 Bug 中最基礎(chǔ)但最嚴(yán)重的問題。極端情況情況下會(huì)產(chǎn)生致命的阻塞性的 Bug(如返回按鈕缺失焦點(diǎn))。通常而言產(chǎn)品上一些按鈕、鏈接、勾選框、圖片、編輯框等需要焦點(diǎn)方便用戶交互。
此外焦點(diǎn)冗余也會(huì)嚴(yán)重影響用戶的使用體驗(yàn),一些裝飾性元素焦點(diǎn)冗余后,用戶的信息篩選效率會(huì)嚴(yán)重降低。通常而言,用戶點(diǎn)擊后無明確響應(yīng)事件的組件不應(yīng)該成為焦點(diǎn)。
「解決方法」:一般情況下,系統(tǒng)會(huì)自動(dòng)給標(biāo)準(zhǔn)控件 UIButton 等交互控件添加焦點(diǎn),其他自定義控件需要手動(dòng)添加/更改。一般情況下手動(dòng)指定屬性isAccessibilityElement為 YES 或者 NO 可解決該問題。
self.isAccessibilityElement = YES;
self.accessibilityLabel = @"點(diǎn)贊"; // 通常焦點(diǎn)描述也會(huì)缺失,需要一并補(bǔ)充。
/// 對(duì)于一些自定義的UI控件,也可以重寫上述兩個(gè)對(duì)象的Get方法。
- (NSString *)accessibilityLabel {
return @"點(diǎn)贊";
}
- (BOOL) isAccessibilityElement {
return YES;
}焦點(diǎn)過細(xì)/焦點(diǎn)合并
焦點(diǎn)合并指的是有相同目的、相同操作的,或具有組合意義的組合視圖,焦點(diǎn)沒有合并的情況,問題描述為“合并焦點(diǎn)”。例如,好友列表中的好友頭像和昵稱應(yīng)合并為一個(gè)焦點(diǎn),二者功能都一樣,都是跳轉(zhuǎn)到個(gè)人資料界面。
「解決方法」:在需要合并焦點(diǎn)的 superView 處將 isAccessibilityElement 設(shè)置為 YES。
self.isAccessibilityElement = YES;
焦點(diǎn)信息錯(cuò)誤 (目的不明確,信息冗余等)
焦點(diǎn)目的不明確是指頁面中的焦點(diǎn)僅朗讀出基本文案,但是未朗讀該控件的類型(按鈕、標(biāo)簽欄、鏈接等),或者未朗讀該焦點(diǎn)響應(yīng)后會(huì)發(fā)生的事件(輕點(diǎn)兩下進(jìn)入詳情頁播放視頻等)。
「解決方法」:參照產(chǎn)品的無障礙標(biāo)注規(guī)范。調(diào)整問題焦點(diǎn)的 accessibilityLabel、accessibilityTraits、accessibilityHint 等字段,從而使焦點(diǎn)信息朗讀準(zhǔn)確。
/// Button // 點(diǎn)贊按鈕未被選中時(shí) self.accessibilityTraits = UIAccessibilityTraitButton; self.accessibilityHint = @"輕點(diǎn)兩下與xxx人一同點(diǎn)贊"; // 點(diǎn)贊按鈕被選中時(shí) self.accessibilityTraits = UIAccessibilityTraitButton|UIAccessibilityTraitSelected; self.accessibilityHint = @"輕點(diǎn)兩下取消點(diǎn)贊"; ///TabBar(包括頂Tab和底Tab) // 當(dāng)對(duì)象為TabBar self.accessibilityTraits = UIAccessibilityTraitTabBar // 被選中的TabBar self.accessibilityTraits = UIAccessibilityTraitTabBar|UIAccessibilityTraitSelected;
焦點(diǎn)停留不當(dāng)
頁面刷新后跑焦點(diǎn)、對(duì)視圖或控件進(jìn)行操作后跑焦點(diǎn),打開新界面焦點(diǎn)停留的位置不適當(dāng),問題描述為“焦點(diǎn)停留不當(dāng)”。例如進(jìn)入一些頁面后,焦點(diǎn)默認(rèn)停留在原位置,或者停留在新頁面的返回按鈕。
「解決方法」:在進(jìn)入界面時(shí)將 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)順序錯(cuò)誤問題
焦點(diǎn)順序不符合邏輯順序時(shí),通常描述為:“焦點(diǎn)順序不符合邏輯順序”;焦點(diǎn)順序不符合視覺順序時(shí),描述為“焦點(diǎn)順序不符合視覺順序”。
「解決方法」:手動(dòng)設(shè)置 accessibilityElements。極端場景下可以主動(dòng)實(shí)現(xiàn) UIAccessibilityContainer 協(xié)議。
/// 普通場景. 切勿在TableView的Cell中使用
self.accessibilityElements = @[View1,View2,View3];
/// 復(fù)雜場景,務(wù)必將三個(gè)方法都實(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)選中時(shí)亂跳問題
該問題主要發(fā)生在 CollectionView 上,一般現(xiàn)象為調(diào)整一個(gè) Cell 的選中態(tài)并 reloadData,焦點(diǎn)會(huì)先轉(zhuǎn)移到一個(gè)隨機(jī)的位置(一般是選中 Cell 的后一個(gè)),而后再跳回正確的位置。
「解決方法」:慎用 UICollectionView、UITableView 的 reloadData。當(dāng)需要刷新 Cell 的選中狀態(tài)時(shí),盡量自己實(shí)現(xiàn)一個(gè) updateVisibleCell。reloadData 時(shí)會(huì)導(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)被覆蓋時(shí)仍可訪問
在西瓜視頻中,浮窗有多種不同的存在形式,如 XIGAlert(隱私彈窗等)、XIGToast(網(wǎng)絡(luò)異常等)、半屏浮窗(鍵盤、清晰度面板、倍速面板等)。在彈窗出現(xiàn)時(shí),用戶可以通過左右滑動(dòng)切換焦點(diǎn)至不可視的視圖。這些視圖產(chǎn)生的相關(guān)事件可能會(huì)使程序崩潰,發(fā)生一些意料之外的事情。
「解決方法」:一般做法為讓底層控件元素失去焦點(diǎn)來達(dá)到屏蔽底層元素的效果,將灰色變暗區(qū)域設(shè)為單個(gè)大焦點(diǎn),標(biāo)簽設(shè)為 “關(guān)閉” 或 “收起” 等提示,雙擊可關(guān)閉浮層。彈窗或彈層時(shí),自動(dòng)使上層容器的第一控件(如標(biāo)題或通知內(nèi)容)獲取焦點(diǎn),視障用戶無須二次切換焦點(diǎn),更符合視障用戶使用體驗(yàn),更加體現(xiàn)人性化。
self.accessibilityViewIsModal = YES
對(duì)蒙層設(shè)置屬性,會(huì)使蒙層的同級(jí) view不響應(yīng) VoiceOver,而蒙層的子 view 可響應(yīng)。如下圖所示,如果希望 E 可以被訪問,CD 不可被訪問,此時(shí)需要設(shè)置 B 的accessibilityViewIsModal為 YES。

嵌套容器 ScrollView 無法跟隨滾動(dòng)問題
在 UICollectionView 中,嵌套一個(gè) UIScrollView 或者 UITableView,焦點(diǎn)在 TableView、ScrollView 中滑動(dòng)時(shí),不會(huì)發(fā)生自動(dòng)滾動(dòng),從而導(dǎo)致頁面發(fā)生白屏等現(xiàn)象。
「解決方法」:使用 accessibilityActivate,在焦點(diǎn)聚焦到一個(gè) Cell 上的時(shí)候,手動(dòng)調(diào)用
scrollToRowAtIndexPath: atScrollPosition: animated:
如果一個(gè) Cell 中包含多個(gè)功能,Cell 還需要進(jìn)行轉(zhuǎn)子適配。
- (BOOL)accessibilityElementDidBecomeFocused {
[self.tableview scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionNone animated:NO];
return YES;
}橫滑拖拽問題(手勢(shì)替代問題)
在應(yīng)用中有許多場景有橫滑手勢(shì),如橫滑刪除,橫滑編輯等。此類事件在 Voice Over 開啟時(shí)無法被響應(yīng)。故需要通過一些其他手段使用戶能夠訪問到橫滑的功能。
「解決方法」:使用轉(zhuǎn)子對(duì)功能進(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的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
iOS開發(fā)中以application/json上傳文件實(shí)例詳解
在和sever后臺(tái)交互的過程中、有時(shí)候、他們需要我們iOS開發(fā)者以“application/json”形式上傳,具體實(shí)例代碼大家參考下本文2017-07-07
iphone的safari瀏覽器中實(shí)現(xiàn)全屏瀏覽的方法
這篇文章主要介紹了iphone的safari瀏覽器中實(shí)現(xiàn)全屏瀏覽的方法,同時(shí)介紹了Add to Home Screen功能的實(shí)現(xiàn)方法,需要的朋友可以參考下2014-06-06
詳解Objective-C設(shè)計(jì)模式編程中對(duì)備忘錄模式的運(yùn)用
這篇文章主要介紹了Objective-C設(shè)計(jì)模式編程中對(duì)備忘錄模式的運(yùn)用,文中結(jié)合了Cocoa框架下應(yīng)用的實(shí)例來加以講解,需要的朋友可以參考下2016-03-03
iOS 原生實(shí)現(xiàn)掃描二維碼和條形碼功能限制掃描區(qū)域
這篇文章主要介紹了iOS 原生實(shí)現(xiàn)掃描二維碼和條形碼功能限制掃描區(qū)域,需要的朋友可以參考下2017-03-03
iOS實(shí)現(xiàn)拖拽View跟隨手指浮動(dòng)效果
這篇文章主要為大家詳細(xì)介紹了iOS實(shí)現(xiàn)拖拽View跟隨手指浮動(dòng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-02-02
快速解決ios微信下audio無法自動(dòng)播放的問題
下面小編就為大家分享一篇快速解決ios微信下audio無法自動(dòng)播放的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-03-03
詳解如何攔截iOS所有網(wǎng)絡(luò)請(qǐng)求
這篇文章主要介紹了詳解如何攔截iOS所有網(wǎng)絡(luò)請(qǐng)求,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-06-06

