【问题标题】:Change order of read items with VoiceOver使用 VoiceOver 更改阅读项目的顺序
【发布时间】:2012-11-07 22:39:05
【问题描述】:

我在屏幕上有一堆按钮,它们在视觉上直观地定位,但 VoiceOver 并没有以直观的顺序阅读。这是因为某些按钮(例如向上和向下)位于彼此上方和下方。然而,画外音似乎开始从左到右,从上到下阅读。

这会导致画外音在“Up”之后朗读“Up”右侧的按钮,而不是紧接着朗读“Down”。

如何强制画外音朗读我想朗读的按钮?我应该提一下,我在画外音中使用了滑动到循环元素功能。

我所有的按钮都是 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;
}

【问题讨论】:

  • 添加一些代码会有所帮助。
  • 会吗?因为我基本上只有一堆函数来初始化按钮并将它们作为子视图添加到主视图中。它们是可访问的,并具有可访问性提示和标签。关于代码你需要知道什么?
  • 这将有助于您启动按钮的方式和顺序
  • 我添加了一些代码。这就是我添加几个按钮的方式。我调用 createSpecialButton,将其返回并添加到视图中。

标签: ios accessibility voiceover


【解决方案1】:

您可以更改设置视图的 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];

如果视图被隐藏,画外音将不会通过它。

【讨论】:

  • 这不适用于我的应用程序...我确实尝试确保所有视图都没有隐藏。
  • 我喜欢这个答案,它比从父视图继承 UIView 简单得多。
【解决方案2】:

对此最简单的答案是创建一个包含您的按钮的UIView 子类,并对来自系统的可访问性调用做出不同的响应。这些重要的调用是:

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

我已经看到了其中一些问题和answered one before,但我还没有看到如何重新排列 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

现在只需将您的按钮包含在此视图的实例中,并将按钮上的标记属性设置为实质上的焦点顺序。

【讨论】:

  • 我想知道这在 iOS 7 中是否仍然有效?我已经输入了所有这些方法,无论我做什么,它们都不会被 iOS 调用,所以它们对任何东西都没有影响。
  • @MusiGenesis 我刚刚在 iPad mini Retina 上测试了这个代码的项目,从 Xcode 5.1.1 运行 7.1,它按预期运行。除非打开 VoiceOver,否则不会调用这些方法。此外,它们可能会被更接近根视图的视图所阻碍。如果没有更多信息,真的无济于事,只能说它们仍然有效。
  • 是否有任何协议指定需要实现哪些所有方法?你能指定任何可能有用的苹果文档链接吗?
  • 哦,使用标签的绝妙方法。唉,我经常将标签用于其他目的(例如做单选按钮组),但这可能会有所帮助。
【解决方案3】:

在 Swift 中,您只需设置视图的 accessiblityElements 数组属性:

view.accessibilityElements = [view1, view2, view3] // 你想要的订单

【讨论】:

  • Swift 只是一种编程语言。这种技术在 Objective-C 中也适用,但是当您没有针对每个视图的插座时,它可能会很痛苦。
  • 在objective-c中,在这种情况下,只需在文字数组view.accessibilityElements = @[view1, view2, view3]之前添加一个@
【解决方案4】:

我知道这是一个旧线程,但我发现最简单的方法是将 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})
    }
}

【讨论】:

    【解决方案5】:

    这并没有直接回答原问题,而是回答了问题的标题:

    当我希望 VoiceOver 向下滑动列时,我一直在使用包含 shouldGroupAccessibilityChildren 集的列的包含视图。

    我希望我早点知道这一点,因为将容器追溯插入自动布局情况可能会很痛苦……

    【讨论】:

      【解决方案6】:

      我尝试Wesley's answer 设置accessibilityElements 的数组,但它对我不起作用。

      Apple 有一些文档Enhancing the Accessibility of Table View Cells 并带有代码示例。基本上,您将单元格(父视图)的可访问性标签设置为子视图的可访问性标签的值。

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

      这对我有用。

      【讨论】:

      • 不要忘记将父视图的isAccessibilityElement 属性设置为true。
      【解决方案7】:

      我认为你可以在情节提要中做到这一点。 VoiceOver 顺序由文档大纲中视图的顺序决定。

      只需按正确的顺序拖放视图层次结构中的视图即可。

      编辑:

      对不起,我不能发布屏幕截图,直到 10 声望。在情节提要中,文档大纲是左侧列出您的场景及其子视图的区域。在这里,子视图按顺序排列在彼此的下方。当您更改此顺序时,VoiceOver 的阅读顺序也会发生变化。

      【讨论】:

      • 您可以添加屏幕截图吗?我看不出你的意思,谢谢。
      • Apple docs 说“容器视图中可访问性元素的顺序应该与呈现给用户的元素的顺序相同,从左上角到右下角。”根据我自己的测试,无论视图的顺序如何,默认情况下画外音都会从左上到右下进行。
      • 我只看到了从左到右,然后从上到下的顺序,我自己。
      • "VoiceOver 顺序由文档大纲中视图的顺序决定" -> 错误(@KenKo 的评论是正确的)
      【解决方案8】:

      我昨天找到了一个方便的方法。类似于@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。然后您可以通过重新排序故事板的视图列表来重新排序它们。

      由于StackView/ScrollView中subview不包含views,所以需要在这个文件中创建一个独立的类。比如下面的 ReorderAccessibilityByStoryBoardStackView。

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

      使用这些代码,您还可以通过按特定顺序添加视图来重新排序代码中添加的视图。

      【讨论】:

      • 样本缺少对super.didAddSubview(subview)的调用。
      猜你喜欢
      • 1970-01-01
      • 2011-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多