web-dev-qa-db-ja.com

VoiceOverで既読アイテムの順序を変更する

画面には、視覚的に直感的に配置されているボタンがたくさんありますが、VoiceOverによって直感的な順序で読み取られません。これは、アップやダウンなどの特定のボタンが上下に配置されているためです。しかし、ナレーションは左から右へ、上から下へと読み始めます。

その結果、ナレーションは直後に「下」を読むのではなく、「上」の後に「上」の右側にあるボタンを読み上げます。

読みたいボタンをナレーションに強制的に読み上げるにはどうすればよいですか?ナレーションで要素をスワイプしてサイクルスルーする機能を使用していることを述べておきます。

すべてのボタンは、UIViewとUIButtonのサブクラスバージョンです。これが私が使用するボタンイニシエーターの例です。ピクセル数は無視してください。これは悪い形ですが、今はピンチです。

UIButton* createSpecialButton(CGRect frame, 
                                 NSString* imageName, 
                                 NSString* activeImageName,
                                 id target,
                                 SEL obClickHandler) 
{
    UIButton* b = [UIButton buttonWithType:UIButtonTypeCustom];
    [b setImage:[GlobalHelper nonCachedImage:imageName ofType:@"png"] 
       forState:UIControlStateNormal];
    [b setImage:[GlobalHelper nonCachedImage:activeImageName ofType:@"png"] 
       forState:UIControlStateHighlighted];
    [b addTarget:target action:obClickHandler forControlEvents:UIControlEventTouchUpInside];    
    b.frame= frame;
    return b;
}


- (UIButton *) createSendButton {
    CGFloat yMarker = 295;

    UIButton* b = createSpecialButton(CGRectMake(160, yMarker, 70, 45),
                                          @"Share_Btn",
                                          @"Share_Selected_Btn",
                                          self,
                                          @selector(sendAction));
    b.accessibilityHint = @"Send it!";
    b.accessibilityLabel = @"Stuff for voiceover to be added";
    [self.view addSubview:b];

    return b;
}
31
Mark S

これに対する最も簡単な答えは、ボタンを含むUIViewサブクラスを作成することであり、システムからのアクセシビリティ呼び出しに異なる応答をします。これらの重要な呼び出しは次のとおりです。

-(NSInteger)accessibilityElementCount
-(id)accessibilityElementAtIndex:
-(NSInteger)indexOfAccessibilityElement:

これらの質問のいくつか、および 前に回答したもの を見てきましたが、VoiceOverフォーカスを並べ替える方法の一般的な例は見ていません。そこで、タグでアクセス可能なサブビューをVoiceOverに公開するUIViewサブクラスを作成する方法の例を次に示します。

AccessibilitySubviewsOrderedByTag.h

#import <UIKit/UIKit.h>
@interface AccessibilitySubviewsOrderedByTag : UIView
@end

AccessibilitySubviewsOrderedByTag.m

#import "AccessibilityDirectional.h"
@implementation AccessibilitySubviewsOrderedByTag {
    NSMutableArray *_accessibilityElements;
}
    //Lazy loading accessor, avoids instantiating in initWithCoder, initWithFrame, or init.
-(NSMutableArray *)accessibilityElements{
    if (!_accessibilityElements){
        _accessibilityElements = [[NSMutableArray alloc] init];
    }
    return _accessibilityElements;
}
// Required accessibility methods...
-(BOOL)isAccessibilityElement{
    return NO;
}
-(NSInteger)accessibilityElementCount{
    return [self accessibilityElements].count;
}
-(id)accessibilityElementAtIndex:(NSInteger)index{
    return [[self accessibilityElements] objectAtIndex:index];
}
-(NSInteger)indexOfAccessibilityElement:(id)element{
    return [[self accessibilityElements] indexOfObject:element];
}
// Handle added and removed subviews...
-(void)didAddSubview:(UIView *)subview{
    [super didAddSubview:subview];
    if ([subview isAccessibilityElement]){
        // if the new subview is an accessibility element add it to the array and then sort the array.
        NSMutableArray *accessibilityElements = [self accessibilityElements];
        [accessibilityElements addObject:subview];
        [accessibilityElements sortUsingComparator:^NSComparisonResult(id obj1, id obj2){
            // Here we'll sort using the tag, but really any sort is possible.
            NSInteger one = [(UIView *)obj1 tag];
            NSInteger two = [(UIView *)obj2 tag];
            if (one < two) return NSOrderedAscending;
            if (one > two) return NSOrderedDescending;
            return NSOrderedSame;
        }];
    }
}
-(void)willRemoveSubview:(UIView *)subview{
    [super willRemoveSubview:subview];
    // Clean up the array. No check since removeObject: is a safe call.
    [[self accessibilityElements] removeObject:subview];
}
@end

次に、このビューのインスタンスでボタンを囲み、ボタンのタグプロパティを基本的にフォーカス順序に設定します。

27
NJones

ビューのaccessibilityElements配列の設定順序を変更できます。

self.view.accessibilityElements = @[self.view1, self.view2, self.view3, self.view4];

または

self.anotherView.accessibilityElements = @[self.label1, self.txtView1, self.label2, self.txtView2];

プログラムで対話を有効にする必要がある場合:

[self.view1 setUserInteractionEnabled:YES];

ビューが非表示の場合、ナレーションは通過しません。

37
Wesley Galindo

Swiftでは、ビューのaccessiblityElements配列プロパティを設定する必要があります:

view.accessibilityElements = [view1, view2, view3] //希望する注文

8

これは元の質問には直接答えませんが、質問のタイトルには答えます。

VoiceOverで列を下にスワイプしたい場合、shouldGroupAccessibilityChildrenが設定された列の包含ビューを使用しています。

コンテナを自動レイアウトの状況にさかのぼって挿入するのは面倒なことがあるので、私が以前にこれを知っていたらよかったのですが…

3
David Dunham

私はaccessibilityElementsの配列を設定する ウェズリーの答え を試しましたが、それは私にとってはうまくいきませんでした。

Appleにはいくつかのドキュメント テーブルビューセルのアクセシビリティの向上 のコード例があります。基本的に、セル(親ビュー)のアクセシビリティラベルを子ビューのアクセシビリティラベルの値に設定します。

[cell setAccessibilityLabel:[NSString stringWithFormat:@"%@, %@", cityLabel, temperatureLabel]];

これは私のために働いたものです。

3
ChrisJF

私はこれが古いスレッドであることを知っていますが、それを行う最も簡単な方法は、UIViewをそのようにサブクラス化することです(Swift 3)。次に、ストーリーボードのメインのUIViewタイプをAccessibiltySubviewsOrderedByTagに変更し、順番に読みたい各サブビューのタグを更新します。

クラスAccessibilitySubviewsOrderedByTag:UIView {

override func layoutSubviews() {

    self.accessibilityElements = [UIView]()
    for accessibilitySubview in self.subviews {
        if accessibilitySubview.isAccessibilityElement {
            self.accessibilityElements?.append(accessibilitySubview)
        }
    }
    self.accessibilityElements?.sort(by: {($0 as AnyObject).tag < ($1 as AnyObject).tag})
}

}

3
TejAces

ストーリーボードでできると思います。 VoiceOverの順序は、ドキュメントアウトラインのビューの順序によって決まります。

ビュー階層内のビューを正しい順序でドラッグアンドドロップするだけです。

編集:

申し訳ありませんが、スクリーンショットは10の評判まで投稿できません。ストーリーボードでは、ドキュメントのアウトラインは、サブビューを含むシーンが一覧表示される左側の領域です。ここでは、サブビューは1つ下に並べられます。この順序を変更すると、VoiceOverの読み上げ順序が変更されます。

2
StefanJ

昨日便利な方法を見つけました。 @TejAcesの回答に似ています。新しいSwiftファイルを作成し、次にこれらのものをそれにコピーします。

import UIKit

extension UIView {
    func updateOrder(_ direction: Bool = true) {
        var tempElements: [Any]? = [Any]()
        let views = (direction) ? subviews : subviews.reversed()
        for aView in views {
            tempElements?.append(aView)
        }
        accessibilityElements = tempElements
    }
}

class ReorderAccessibilityByStoryBoardView: UIView {
    override func didAddSubview(_ subview: UIView) {
        updateOrder()
        super.didAddSubview(subview)
    }
}

UIView(並べ替えるビューを含む)のクラスをReorderAccessibilityByStoryBoardViewとして設定します。次に、ストーリーボードのビューリストを並べ替えることで、並べ替えることができます。

view list

サブビューにはStackView/ScrollViewのビューが含まれていないため、このファイルで独立したクラスを作成する必要があります。以下のReorderAccessibilityByStoryBoardStackViewなど。

class ReorderAccessibilityByStoryBoardStackView: UIStackView {
    override func didAddSubview(_ subview: UIView) {
        updateOrder(false)
        super.didAddSubview(subview)
    }
}

これらのコードを使用して、コードに追加されたビューを特定の順序で追加することにより、ビューの順序を変更することもできます。

1
Jinyu Meng