J'ai un tas de boutons sur l'écran qui sont positionnés visuellement intuitivement mais ne sont pas lus dans un ordre intuitif par VoiceOver. En effet, certains boutons comme Up et Down sont placés au-dessus et en dessous l'un de l'autre. Cependant, la voix off commence à lire de gauche à droite, de haut en bas, semble-t-il.
Il en résulte que la voix off lit le bouton à droite de "Up" après "Up", au lieu de lire "Down" immédiatement après.
Comment forcer la voix off à lire le bouton que je veux lire? Je dois mentionner que j'utilise la fonction de balayage pour parcourir les éléments sur la voix off.
Tous mes boutons sont des versions sous-classées de UIView et UIButton. Voici un exemple d'initiateur de bouton que j'utilise. Ignorez le nombre de pixels - je sais que c'est une mauvaise forme, mais je suis dans un pincement pour le moment:
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;
}
La réponse la plus simple consiste à créer une sous-classe UIView
qui contient vos boutons et répond différemment aux appels d'accessibilité du système. Ces appels importants sont:
-(NSInteger)accessibilityElementCount
-(id)accessibilityElementAtIndex:
-(NSInteger)indexOfAccessibilityElement:
J'ai vu quelques-unes de ces questions, et a répondu à une avant , mais je n'ai pas vu d'exemple générique sur la façon de réorganiser le focus VoiceOver. Voici donc un exemple de création d'une sous-classe UIView
qui expose ses sous-vues accessibles à VoiceOver par balise.
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
Maintenant, insérez simplement vos boutons dans une instance de cette vue et définissez la propriété de balise sur vos boutons pour être essentiellement l'ordre de focus.
Vous pouvez modifier l'ordre en définissant le tableau accessibilityElements de la vue:
self.view.accessibilityElements = @[self.view1, self.view2, self.view3, self.view4];
ou
self.anotherView.accessibilityElements = @[self.label1, self.txtView1, self.label2, self.txtView2];
Si vous devez définir l'interaction activée par programme:
[self.view1 setUserInteractionEnabled:YES];
Si la vue est cachée, la voix hors champ ne la traversera pas.
Dans Swift il vous suffit de définir la propriété du tableau accessiblityElements de view:
view.accessibilityElements = [view1, view2, view3]
// commande que vous souhaitez avoir
Cela ne répond pas directement à la question d'origine, mais cela répond au titre de la question:
Lorsque je souhaite que VoiceOver glisse vers le bas d'une colonne, j'utilise une vue conteneur pour la colonne avec shouldGroupAccessibilityChildren
set.
J'aurais aimé le savoir plus tôt, car il peut être pénible d'insérer rétroactivement des conteneurs dans une situation de mise en page automatique…
J'ai essayé la réponse de Wesley de définir le tableau du accessibilityElements
mais cela n'a pas fonctionné pour moi.
Apple a de la documentation Amélioration de l'accessibilité des cellules de vue de table avec un exemple dans le code. Fondamentalement, vous définissez l'étiquette d'accessibilité de la cellule (la vue parent) sur les valeurs des étiquettes d'accessibilité des vues enfant.
[cell setAccessibilityLabel:[NSString stringWithFormat:@"%@, %@", cityLabel, temperatureLabel]];
C'est ce qui a fonctionné pour moi.
Je sais que c'est un vieux fil, mais j'ai trouvé que la façon la plus simple de le faire est de sous-classer UIView en tant que tel (Swift 3). Ensuite, modifiez simplement votre type UIView principal dans le storyboard en AccessibiltySubviewsOrderedByTag et mettez à jour les balises dans chaque sous-vue que vous souhaitez lire dans l'ordre.
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})
}
}
Je pense que vous pouvez le faire dans le storyboard. L'ordre VoiceOver est déterminé par l'ordre des vues dans le plan du document.
Faites simplement glisser et déposez les vues dans la hiérarchie des vues dans le bon ordre.
Éditer:
Désolé, je ne peux pas poster de captures d'écran avant 10 points de réputation. Dans le storyboard, le plan du document est la zone à gauche où vos scènes avec leurs sous-vues sont répertoriées. Ici, les sous-vues sont ordonnées les unes au-dessous des autres. Lorsque vous modifiez cet ordre, l'ordre de lecture de VoiceOver change.
J'ai trouvé un moyen pratique hier. Similaire à la réponse de @TejAces. Créez un nouveau fichier Swift, puis copiez-y ces éléments.
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)
}
}
Définissez la classe de UIView (contient les vues que vous souhaitez réorganiser) en tant que ReorderAccessibilityByStoryBoardView. Vous pouvez ensuite les réorganiser en réorganisant la liste des vues du storyboard.
Étant donné que la sous-vue ne contient pas de vues dans StackView/ScrollView, vous devez créer une classe indépendante dans ce fichier. Tels que ReorderAccessibilityByStoryBoardStackView ci-dessous.
class ReorderAccessibilityByStoryBoardStackView: UIStackView {
override func didAddSubview(_ subview: UIView) {
updateOrder(false)
super.didAddSubview(subview)
}
}
Avec ces codes, vous pouvez également réorganiser les vues ajoutées dans le code en les ajoutant dans un ordre spécifique.