iOS Accessibility易用性 VoiceOver(盲人模式)粗淺適配

1、打開盲人模式: 

手機(6s iOS12.4)路徑:設置->通用->輔助功能(底部)->輔助功能快捷鍵->勾選旁白(voiceOver)bash


這裏須要特別說明一下,在通用列表進入輔助功能列表頁時,頂部也有個旁白選項能夠打開該功能,可是這裏最好仍是按照我圖示的方式來打開旁白功能。由於正如紅框框出來的那樣,按照我這種方式打開旁白功能是能夠直接快捷鍵(連按三下home鍵)開啓關閉的,這在你的開發當中提高的效率可不是一點半點,由於盲人模式下的使用方式跟正常差距仍是比較大的,好比你要調試一個比較深層級的頁面,能夠先以正常方式進入到目的頁面再按三下home鍵開啓旁白。若是以另一種方式打開旁白,而沒有開啓快捷鍵的話,你必須以盲人方式進入目的頁面,至關的蛋疼。app

2、屬性解讀

  • isAccessibilityElement 設置是否支持盲人模式 ,必須設置爲YES系統才能聚焦到該元素。須要注意的是UIView是默認關閉的,UIButton、UILabel默認打開。
  • accessibilityLabel 用來描述控件是什麼.UIButton和lable會默認從title和text中獲取,textField從輸入框的內容獲取..當元素得到焦點時會第一個播放。
  • accessibilityTraits 元素的特徵.如按鈕,連接等.元素獲取焦點後會在第二個播放.因爲會播放按鈕等,所以accessibilityLabel能夠不用添加連接的描述,直接使用系統描述的特徵,如:lable爲登錄,traint爲按鈕,系統會播放」登錄->按鈕」。
  • accessibilityHint 至關因而一個附加說明.第三個朗讀,默認爲nil。
  • accessibilityValue 元素的值.用在UISlider,UITextField等組件上.用來描述元素的值。
  • accessibilityFrame 元素的frame,當系統聚焦到當前元素時,會有一個黑色的外框,該值就是聚焦框的大小。當元素太小時能夠經過設置該frame使得容易點擊,這個不會改變app的UI.若是不想讓系統讀取到該元素,能夠設置frame爲CGRectZero。

3、特殊處理

  1. 若是是商品列表頁,對應cell想要被聚焦後直接輸出提示文案,只須要將本身設置爲易用性元素,即self.isAccessibilityElement = YES;而後在能拿到業務數據的地方設置提示文案就好:self.accessibilityLabel = [NSString stringWithFormat:@"product name %@ %@",eventProduct.name,self.priceLbl.attributedText.string];
  2. 有的視圖若是是本身繪製的話,像咱們App裏面購物車底部的支付按鈕,這是用UIBezierPath畫出來的。這種處理就會稍微麻煩一點。須要實現一個定義在UIAccessibilityContainer.h  文件中的非正式協議,不須要用尖括號遵循協議,只用實現如下幾個方法就行。雖然系統聚焦框跟按鈕實際形狀有點誤差,可是影響不大。好在這種狀況下,原來定義的點擊事件也不須要特別處理。

    - (BOOL)isAccessibilityElement {    
        return NO;
    }     
    - (NSArray *)accessibilityElements {    
        return self.accessArray;
    }
    - (NSInteger)accessibilityElementCount {    
        return self.accessArray.count;
    }     
    
    @property (nonatomic, strong) NSArray           *accessArray;     
    - (NSArray *)accessArray {    
        if (_accessArray) {        
            return _accessArray;    
        }    
        UIAccessibilityElement *ele1 = [[UIAccessibilityElement alloc] initWithAccessibilityContainer:self.bgView];    
        CGRect rect1 = CGRectMake(CGRectGetMinX(self.bgView.frame), CGRectGetMinY(self.bgView.frame), CGRectGetWidth(self.bgView.frame)/2.0, CGRectGetHeight(self.bgView.frame)); 
        ele1.accessibilityFrame = UIAccessibilityConvertFrameToScreenCoordinates(rect1, self.bgView);    
        ele1.accessibilityLabel = @"PayPal";
        //這裏最好加上這句,由於盲人用戶聽到這是按鈕,才知道它可點擊
        ele1.accessibilityTraits = UIAccessibilityTraitButton;        
    
        UIAccessibilityElement *ele2 = [[UIAccessibilityElement alloc] initWithAccessibilityContainer:self];    
        CGRect rect2 = CGRectMake(CGRectGetMidX(self.bgView.frame), CGRectGetMinY(self.bgView.frame), CGRectGetWidth(self.bgView.frame)/2.0, CGRectGetHeight(self.bgView.frame));  
        ele2.accessibilityFrame = UIAccessibilityConvertFrameToScreenCoordinates(rect2, self.bgView);    
        ele2.accessibilityLabel = PPString(SHOPPINGCART_PROCEEDTOCHECKOUT); 
        ele2.accessibilityTraits = UIAccessibilityTraitButton;       _accessArray = @[ele1, ele2];    
        return _accessArray;
    }複製代碼



  3. 流程打斷後的聚焦變化。當進入一個新界面後,系統默認會聚焦到左上角第一個元素,通常都是關閉按鈕或者退出按鈕。咱們業務流程規定,在用戶結帳前,必須登陸才能執行後續流程。因此若是一個盲人遊客狀態下加購了商品到購物車,此時點擊結帳。會先彈出登陸註冊彈窗讓其登陸。若是沿用系統的默認聚焦設定,將會很是不友好:由於用戶先聽到checkout button,點擊後竟然又直接聽到了close button,下意識確定會有點懵逼。因此這裏咱們最好手動調整聚焦。處理方式:我直接將帳號輸入欄的textField的accessibilityLabel設置爲了@"Welcome, sign in or register to continue shopping.",而後在登陸註冊控制器的viewDidAppear中調用方法UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, self.signInDataSource.emailTextField); 將界面聚焦到了帳號輸入欄。ide

  4. 在一些特殊流程階段,用戶返回後數據會丟失,因此在其點擊返回按鈕時,會給一個確認彈窗,當前項目中不少確認彈窗都是咱們本身仿UIAlertView樣式寫的,而後添加在根window。因此這裏也須要特別處理一下,不然彈窗出現之後靠左右掃的手勢很難才能切換到咱們的自定義彈窗上。其實核心方法跟上面同樣,自定義彈窗添加到根window之後調用UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, alertVew.titleLbl);方法將焦點聚焦到彈窗標題上。post


4、寫在最後

這是我在盲人模式適配中的一點小經驗,作以前在網上搜的資料比較少也比較老,因此想着碰到的問題記錄一下,若是能恰巧幫助到碰到這個問題的朋友那就更好了。忽然要適配盲人模式的原由實際上是由於咱們的App和網站在美國被別人告了,說是不支持盲人使用,因此也只是大概適配了一下購物下單主流程,沒有作得特別細。若是涉及到更細節深度的問題可能須要本身仔細閱讀UIKit下的UIAccessibility.h文件了。網站


5、補充

流程切換致使的屏幕焦點切換,且須要加提示語音的問題。出如今咱們App的詳情頁,具體情景就是在詳情頁點擊加購按鈕的時候,會彈起一個半彈窗,讓用戶選擇顏色、尺寸、數量等。ui


點擊確認會加購成功,收起半彈窗並將焦點設置在詳情頁的加購按鈕;同時產品要求出一個「add to cart successfully」的語音反饋。atom


那麼如今的問題就是怎麼樣在屏幕焦點從半彈窗的加購按鈕切換爲詳情頁加購按鈕的狀況下(此時系統在讀的提示爲「Add to Cart ,Button」),加入這個「add to cart successfully」的語音反饋。一開始我找到的是UIAccessibilityConstants.h文件下的UIAccessibilityElementFocusedNotification ,至關於在屏幕焦點切換時會發出通知。在它的下面還有兩個東西:
spa

// The corresponding value is the element that is now focused by the assistive technology.
UIKIT_EXTERN NSString *const UIAccessibilityFocusedElementKey NS_AVAILABLE_IOS(9_0);

// The corresponding value is the element that had previously been focused by the assistive technology.
UIKIT_EXTERN NSString *const UIAccessibilityUnfocusedElementKey NS_AVAILABLE_IOS(9_0);複製代碼

看註釋很容易想到他們三個是合在一塊兒用的。因此個人解決方案就是詳情頁註冊了UIAccessibilityElementFocusedNotification通知,在接收到通知的時候,用這兩個key取到焦點切換先後的元素,若是符合條件的話,就延遲發送一個語音提示。主要代碼以下:調試

//盲人模式下屏幕焦點切換通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(postAddToCartSuccessedVoiceTips:) name:UIAccessibilityElementFocusedNotification object:nil];

- (void)postAddToCartSuccessedVoiceTips:(NSNotification *)noti {
    UIButton *previous = noti.userInfo[UIAccessibilityUnfocusedElementKey];
    UIButton *current = noti.userInfo[UIAccessibilityFocusedElementKey];
    BOOL previousIsAddToCart = ISCLASS([UIButton class], previous) && ([previous.currentTitle isEqualToString:PPString(OK_STRING)] || [previous.currentTitle isEqualToString:PPString(PRODUCTDETAIL_ADDTOCART)]);
    BOOL currentIsAddToCart = ISCLASS([UIButton class], current) && [current.currentTitle isEqualToString:PPString(PRODUCTDETAIL_ADDTOCART)];
    if (previousIsAddToCart && currentIsAddToCart) {
        //判斷屏幕焦點是從半彈窗的加購按鈕 切換到的 詳情頁Add To cart按鈕 ,須要提示加購成功語音
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, kAddToCartSuccessedTips);
        });
    }
}

複製代碼

可是這種粗糙的方式會形成一個問題,若是在2.5秒的時間內系統沒有讀完「Add to Cart ,Button」這句話的時候,你後續發送的語音提示會打斷正在朗讀的提示。或者若是「Add to Cart ,Button」朗讀速度比較快的話,要等零點幾秒才能聽到加購成功的提示。因此這是一種不夠優雅的解決方式。若是有更好的解決方案,還請不吝賜教!code

相關文章
相關標籤/搜索