Изменить порядок чтения элементов с помощью VoiceOver
У меня есть куча кнопок на экране, которые позиционируются интуитивно визуально, но не читаются в интуитивном порядке VoiceOver. Это связано с тем, что некоторые кнопки, такие как "Вверх" и "Вниз", расположены над и под друг другом. Тем не менее, голос за кадром начинает читать слева направо, сверху донизу, кажется.
Это приводит к тому, что голос за кадром просматривает кнопку справа от "Вверх" после "Вверх", вместо того, чтобы сразу же читать "Вниз".
Как заставить голос за кадром читать кнопку, которую я хочу читать? Я должен упомянуть, что я использую функцию swipe-to-cycle-through-elements для озвучивания.
Все мои кнопки - это подклассы версий 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;
}
Ответы
Ответ 1
Самый простой ответ на этот вопрос заключается в создании подкласса 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
Теперь просто вставьте свои кнопки в экземпляр этого представления и установите свойство тега на ваших кнопках, чтобы быть по существу порядком фокусировки.
Ответ 2
Вы можете изменить настройку порядка массива 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];
Если вид скрыт, голос не пройдет через него.
Ответ 3
В Swift вам просто нужно установить свойство access accessiblityElements свойства:
view.accessibilityElements = [view1, view2, view3]
//закажите, что хотите
Ответ 4
Я попробовал ответ Уэсли об установке массива accessibilityElements
, но это не сработало для меня.
В Apple есть документация Повышение доступности ячеек таблицы с примером в коде. В основном вы устанавливаете метку доступности ячейки (родительское представление) на значения ярлыков доступности дочерних представлений.
[cell setAccessibilityLabel:[NSString stringWithFormat:@"%@, %@", cityLabel, temperatureLabel]];
Это то, что сработало для меня.
Ответ 5
Я думаю, вы можете сделать это в раскадровке. Порядок VoiceOver определяется порядком представлений в контуре документа.
Просто перетащите представления в иерархии представлений в правильном порядке.
Edit:
Извините, я не могу опубликовать скриншоты до 10 репутации. В раскадровке контур документа - это область слева, где перечислены ваши сцены с их подзонами. Здесь подзоны упорядочены один под другим. Когда вы измените этот порядок, порядок чтения VoiceOver изменится.
Ответ 6
Я знаю, что это старый поток, но я обнаружил, что самый простой способ сделать это - подкласс 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})
}
}
Ответ 7
Вчера я нашел удобный способ. Как и ответ @TejAces. Создайте новый быстрый файл, а затем скопируйте в него все.
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()
}
}
Задайте класс UIView (содержит виды, которые вы хотите переупорядочить) как ReorderAccessibilityByStoryBoardView. Затем вы можете переупорядочить их, переупорядочив список раскадровки.
![view list]()
Поскольку subview не содержит представлений в StackView/ScrollView, вам нужно сделать независимый класс в этом файле. Например, ReorderAccessibilityByStoryBoardStackView ниже.
class ReorderAccessibilityByStoryBoardStackView: UIStackView {
override func didAddSubview(_ subview: UIView) {
updateOrder(false)
}
}
С помощью этих кодов вы также можете изменить порядок, добавленный в код, добавив их в определенном порядке.
Ответ 8
Это напрямую не отвечает на исходный вопрос, но отвечает на заголовок вопроса:
Когда я хочу, чтобы VoiceOver удалял столбец, я использовал содержащее представление для столбца с shouldGroupAccessibilityChildren
.
Хотел бы я знать это раньше, потому что это может быть болью, чтобы задним числом вставлять контейнеры в ситуацию автоотключения...