Променете реда на прочетените елементи с VoiceOver

Имам куп бутони на екрана, които са позиционирани интуитивно визуално, но не се четат в интуитивен ред от 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;
}

person Mark S    schedule 07.11.2012    source източник
comment
Добавянето на някакъв код би помогнало.   -  person Ryan B    schedule 10.11.2012
comment
Би ли го направила? Защото по същество просто имам куп функции, които инициират бутони и ги добавят към основния изглед като подизгледи. Те са направени да бъдат достъпни и имат съвети и етикети за достъпност. Какво трябва да знаете за кода?   -  person Mark S    schedule 12.11.2012
comment
Би помогнало по отношение на начина и реда, в който инициирате бутоните   -  person Ryan B    schedule 14.11.2012
comment
Добавих малко код. Ето как добавям няколко от моите бутони. Извиквам createSpecialButton, връщам го и го добавям към изгледа.   -  person Mark S    schedule 16.11.2012


Отговори (9)


Най-лесният отговор на това се крие в създаването на подклас UIView, който съдържа вашите бутони и отговаря по различен начин на извикванията за достъпност от системата. Тези важни обаждания са:

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

Виждал съм няколко от тези въпроси и отговорих на един преди, но не съм виждал общ пример за това как за да пренаредите фокуса на VoiceOver. И така, ето пример за това как да създадете UIView подклас, който излага своите достъпни подизгледи на VoiceOver по етикет.

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

Сега просто оградете вашите бутони в екземпляр на този изглед и задайте свойството на етикета на вашите бутони да бъде по същество редът на фокусиране.

person NJones    schedule 15.11.2012
comment
Благодаря NJones! Все още не съм го приложил, но вярвам на думата ви. - person Mark S; 19.11.2012
comment
@josef Благодаря, че посочи това. Редактирах отговора си, за да коригирам тези несъответствия. - person NJones; 05.01.2014
comment
Чудя се дали това все още работи в iOS 7? Въведох всички тези методи и те просто никога не се извикват от iOS, независимо какво правя, така че нямат ефект върху нищо. - person MusiGenesis; 12.04.2014
comment
@MusiGenesis Току-що тествах проекта, от който е този код, на iPad mini Retina, работещ с 7.1 от Xcode 5.1.1, и той работи според очакванията. Тези методи няма да бъдат извикани, освен ако VoiceOver не е включен. Освен това те могат да бъдат възпрепятствани от изгледи, които са по-близо до основния изглед. Не мога да помогна много без повече информация, освен да кажа, че все още работят. - person NJones; 16.04.2014
comment
Има ли някакъв протокол, който определя кои всички методи трябва да бъдат внедрени? Можете ли да посочите някакви връзки към документи на Apple, които биха могли да бъдат полезни? - person Dynamite; 27.08.2014
comment
О, страхотен подход с помощта на етикети. Уви, често използвам тагове за други цели (като например създаване на групи с радио бутони), но това може да помогне. - person David Dunham; 12.08.2017

Можете да промените реда на настройката на масива accessibilityElements на изгледа:

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

or

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

Ако трябва да зададете програмно активирано взаимодействие:

[self.view1 setUserInteractionEnabled:YES];

Ако изгледът е скрит, гласът няма да премине през него.

person Wesley Galindo    schedule 21.07.2015
comment
точно това търсех! Работи като скъпоценен камък! - person Nitin Alabur; 06.08.2015
comment
това не работи за моето приложение...опитах се да се уверя, че всички изгледи не са скрити. - person lifemoveson; 20.11.2015
comment
Харесва ми този отговор, той е много по-прост от подкласирането на UIView от superview. - person Zoltán; 15.11.2017

В Swift просто трябва да зададете свойството accessiblityElements array на изгледа:

view.accessibilityElements = [view1, view2, view3] // поръчка, която желаете да имате

person Karthik damodara    schedule 18.07.2017
comment
Swift е просто език за програмиране. Тази техника работи и в Objective-C, но може да бъде болка, когато нямате изходи за всеки изглед. - person David Dunham; 12.08.2017
comment
В objective-c в този случай просто добавете @ преди литералния масив view.accessibilityElements = @[view1, view2, view3] - person nacho4d; 10.08.2018

Това не отговаря директно на първоначалния въпрос, но отговаря на заглавието на въпроса:

Когато искам VoiceOver да плъзне надолу колона, използвам съдържащ изглед за колоната с shouldGroupAccessibilityChildren набор.

Иска ми се да знаех това по-рано, защото може да бъде болка да вмъкнете контейнери със задна дата в ситуация на автоматично оформление...

person David Dunham    schedule 12.08.2017

Знам, че това е стара тема, но открих, че най-лесният начин да го направя е да подкласифицирам UIView като такъв (Swift 3). След това просто променете основния си тип UIView в сценария на AccessibiltySubviewsOrderedByTag и актуализирайте таговете във всеки подизглед, който искате да прочетете по ред.

class 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})
    }
}
person TejAces    schedule 09.02.2018

Опитах отговора на Уесли за задаване на масива от accessibilityElements, но не работи за мен.

Apple разполага с малко документация Подобряване на достъпността на клетките за изглед на таблица с пример в кода. По принцип задавате етикета за достъпност на клетката (родителския изглед) на стойностите на етикетите за достъпност на дъщерните изгледи.

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

Това е, което работи за мен.

person ChrisJF    schedule 22.12.2015
comment
Не забравяйте да настроите свойството isAccessibilityElement на родителския изглед на true. - person Daniel T.; 19.08.2016

Мисля, че можете да го направите в сценария. Редът на VoiceOver се определя от реда на изгледите в очертанията на документа.

Просто плъзнете и пуснете изгледите в йерархията на изгледите в правилния ред.

Редактиране:

Съжалявам, не мога да публикувам екранни снимки до 10 репутация. В разкадровката контурът на документа е областта отляво, където са изброени вашите сцени с техните подизгледи. Тук подизгледите са подредени един под друг. Когато промените този ред, редът на четене на VoiceOver ще се промени.

person StefanJ    schedule 16.02.2015
comment
Можете ли да добавите екранна снимка? Не мога да разбера къде имаш предвид, благодаря. - person nycynik; 16.02.2015
comment
Документите на Apple казват този ред на елементите за достъпност в контейнера изгледът трябва да бъде същият като реда, в който представените елементи се представят на потребителя, от горния ляв до долния десен ъгъл. От моето собствено тестване гласът по подразбиране ще прави отгоре вляво до долу вдясно, независимо от реда на изгледите. - person Ken Ko; 30.05.2015
comment
Виждал съм само реда отляво надясно, след това отгоре надолу. - person David Dunham; 07.03.2017
comment
Редът на VoiceOver се определя от реда на изгледите в очертанията на документа -› Грешен (коментарът на @KenKo е правилен) - person Hassan Tareq; 03.04.2020

Вчера намерих удобен начин. Подобно на отговора на @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. След това можете да ги пренаредите, като пренаредите списъка с изгледи на сценария.

преглед на списък

Тъй като subview не съдържа изгледи в StackView/ScrollView, трябва да направите независим клас в този файл. Като например ReorderAccessibilityByStoryBoardStackView долу.

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

С тези кодове можете също да пренаредите изгледите, добавени в кода, като ги добавите в определен ред.

person Jinyu Meng    schedule 02.09.2018
comment
В пробите липсва обаждане до super.didAddSubview(subview). - person mttcrsp; 29.08.2019

Swift5 можете да зададете свойството на масива accessiblityElements на изгледа:
също работи, когато родителският изглед е UIStackView

view.accessibilityElements = [view1, label2, button3...] // поръчка, която желаете да имате

person Zgpeace    schedule 01.06.2021