ios 使用VoiceOver更改已读项目的顺序

frebpwbc  于 2023-01-14  发布在  iOS
关注(0)|答案(9)|浏览(189)

我在屏幕上有一堆按钮,它们的位置直观,但画外音并不是按照直观的顺序来阅读的。这是因为某些按钮,如“向上”和“向下”,是上下排列的。然而,画外音似乎是从左到右,从上到下开始阅读的。
这会导致画外音在“向上”之后阅读到“向上”右侧的按钮,而不是紧接着读到“向下”。
如何强制画外音读取我想要读取的按钮?我应该提到我正在使用画外音上的滑动循环元素功能。
我所有的按钮都是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;
}
sd2nnvve

sd2nnvve1#

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

**注:**如果视图被隐藏,则VoiceOver将无法通过它。

tez616oj

tez616oj2#

最简单的解决方法是创建一个UIView子类,其中包含按钮,并以不同的方式响应来自系统的可访问性调用。

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

我见过其中的一些问题和answered one before,但我还没有看到如何重新排序VoiceOver焦点的一般示例。因此,这里是一个如何创建UIView子类的示例,该子类按标签向VoiceOver显示其可访问的子视图。

辅助功能子视图按标签排序.h

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

辅助功能子视图按标签排序.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

现在只需将按钮包含在该视图的示例中,并将按钮上的tag属性设置为焦点顺序。

ef1yzkbh

ef1yzkbh3#

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

view.accessibilityElements = [view1, view2, view3] // order you wish to have
uttx8gqw

uttx8gqw4#

我知道这是一个老线索,但我发现最简单的方法是子类化UIView,然后简单地将故事板中的主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})
    }
}
5tmbdcev

5tmbdcev5#

这没有直接回答原始问题,但回答了问题的标题:
当我想让VoiceOver向下轻扫某列时,我一直在为设置了shouldGroupAccessibilityChildren的列使用包含视图。
我希望我早一点知道这一点,因为将容器追溯插入到自动布局的情况下可能会很痛苦...

7xllpg7q

7xllpg7q6#

我尝试使用Wesley's answer来设置accessibilityElements的数组,但它对我不起作用。
苹果有一些文档增强表格视图单元格的可访问性,其中有一个代码示例。基本上,你可以将单元格(父视图)的可访问性标签设置为子视图的可访问性标签的值。

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

这对我很有效。

qvtsj1bj

qvtsj1bj7#

昨天我发现了一个方便的方法。类似于@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中的视图,所以您需要在此文件中创建一个独立的类,例如下面的ReorderAccessibilityByStoryBoardStackView。

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

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

i2loujxw

i2loujxw8#

我想你可以在情节提要中做。画外音的顺序是由文档大纲中视图的顺序决定的。
只需按照正确的顺序拖放视图层次结构中的视图即可。
编辑:
抱歉,我不能发布10个声望之前的截屏。在情节提要中,文档大纲是左侧的区域,其中列出了您的场景及其子视图。在这里,子视图按一个在另一个下面的顺序排列。当您更改此顺序时,旁白的阅读顺序也会更改。

fwzugrvs

fwzugrvs9#

雨燕5.x

the advice of ChrisJF之后,我编写了一个小扩展,以绕过正确顺序阅读项周围的Apple bug。

extension UIView {
    func setAccessibilityOrder(_ arrayViews:[Any]?){
        self.accessibilityElements = arrayViews
        let arrayStrings:[String] = arrayViews?.map { String(($0 as AnyObject).accessibilityLabel ?? "") } ?? []
        let formatList = arrayStrings.map { _ in "%@" }.joined(separator: ", ")
        self.accessibilityLabel = String(format: formatList, arguments:arrayStrings)
        self.isAccessibilityElement = true
    }
}

用法:

view1.accessibilityLabel = "my view 1"
label2.accessibilityLabel = "my label 2"
button3.accessibilityLabel = "my button 3"
let order = [view1, label2, button3]
self.setAccessibilityOrder(order) // or self.view.setAccessibilityOrder(order) if you are on a parent controller

相关问题