首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >表视图中的UIAccessibilityContainer

表视图中的UIAccessibilityContainer
EN

Stack Overflow用户
提问于 2011-05-03 16:12:44
回答 2查看 7.1K关注 0票数 4

我试图在UITableViewCell中放置一个自定义视图,该视图当然位于UITableView中。我想让这个自定义视图可以访问,所以我需要将它变成一个UIAccessibilityContainer (因为它包含了几个没有作为自己的UIViews实现的可视元素)。

当我这样做时,每当表滚动时,元素的位置就会变得混乱。在使用VoiceOver分页浏览元素时,它将自动滚动表,试图在屏幕上对所选元素进行居中,但是VoiceOver认为元素的位置不再与其视觉位置一致的轮廓。

请注意,在屏幕截图中,检查人员说“第4行,元素2”,但是突出显示的区域是第7行中的一些随机区域,因为这恰好是第4行自动滚动表之前的位置。

我的想法是,当表视图滚动时,我可能不得不使用UIAccessibilityPostNotification()发布布局更改,但当我不使用UIAccessibilityContainer时,我不必这样做,而且感觉我不应该这样做,而系统应该为我处理这个问题--但是,UIAccessibilityElement需要在屏幕坐标中设置它的accessibilityFrame,这似乎给事情带来了麻烦。(额外的问题是:为什么API是这样设计的?为什么不定义相对于元素的容器或类似的框架呢?( Arg.)

这是自定义视图的实现,以防这里有什么东西会导致问题。对于整个项目(Xcode 4),单击此处

代码语言:javascript
运行
复制
@implementation CellView
@synthesize row=_row;

- (void)dealloc
{
    [_accessibleElements release];
    [super dealloc];
}

- (void)setRow:(NSInteger)newRow
{
    _row = newRow;

    [_accessibleElements release];
    _accessibleElements = [[NSMutableArray arrayWithCapacity:0] retain];

    for (NSInteger i=0; i<=_row; i++) {
        UIAccessibilityElement *element = [[UIAccessibilityElement alloc] initWithAccessibilityContainer:self];
        element.accessibilityValue = [NSString stringWithFormat:@"Row %d, element %d", _row, i];
        [_accessibleElements addObject:element];
        [element release];
    }    

    [self setNeedsDisplay];
}

- (void)drawRect:(CGRect)rect
{
    [[UIColor lightGrayColor] setFill];
    UIRectFill(self.bounds);

    [[UIColor blackColor] setFill];
    NSString *info = [NSString stringWithFormat:@"Row: %d", _row];
    [info drawAtPoint:CGPointZero withFont:[UIFont systemFontOfSize:12]];

    [[[UIColor whiteColor] colorWithAlphaComponent:0.5] setFill];
    NSInteger x=0, y=0;
    for (NSInteger i=0; i<=_row; i++) {
        CGRect rect = CGRectMake(12+x, 22+y, 30, 30);

        UIAccessibilityElement *element = [_accessibleElements objectAtIndex:i];
        element.accessibilityFrame = [self.window convertRect:[self convertRect:rect toView:self.window] toWindow:nil];

        UIRectFill(rect);
        x += 44;

        if (x >= 300) {
            x = 0;
            y += 37;
        }
    }
}

- (BOOL)isAccessibilityElement
{
    return NO;
}

- (NSInteger)accessibilityElementCount
{
    return [_accessibleElements count];
}

- (id)accessibilityElementAtIndex:(NSInteger)index
{
    return [_accessibleElements objectAtIndex:index];
}

- (NSInteger)indexOfAccessibilityElement:(id)element
{
    return [_accessibleElements indexOfObject:element];
}

@end

编辑:我应该注意到,我尝试过在-indexOfAccessibilityElement:-accessibilityElementAtIndex:中更新元素的accessibilityFrame的变体,它的思想是,VoiceOver将在元素需要时以某种方式请求它,这将是更新内容的好时机。然而,这似乎也不起作用。我希望也许VoiceOver会自动要求重新绘制东西,但这似乎也不起作用。(将位置设置代码放在-drawRect:中的想法来自于我在WWDC上看到的关于这个问题的东西,但我不清楚这是“最佳实践”还是刚好方便。)

EN

回答 2

Stack Overflow用户

发布于 2011-11-21 09:27:52

通过向可访问性方法添加一些副作用,并通过表滚动委托的协作,解决了您所描述的问题。在drawRect方法中,我计算矩形的局部坐标,因此我不需要在那里转换坐标,只需计算它们相对于单元格的左上角。

然后,我修改了访问器以更新框架,其副作用如下(注意y重置):

代码语言:javascript
运行
复制
- (id)accessibilityElementAtIndex:(NSInteger)index
{
    UIAccessibilityElement *element = [accesible_items_ get:index];
    CGRect rect = element.accessibilityFrame;
    rect.origin.y = 0;
    element.accessibilityFrame = [self.window
        convertRect:rect fromView:self];
    return element;
}

虽然这对于初始视图很好,但在用户滚动时仍然会得到替换的框架,因此在表视图控制器中实现以下滚动委托:

代码语言:javascript
运行
复制
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    // This loop has a side effects, see the cell accesor code.
    for (id cell in self.tableView.visibleCells)
        for (int f = 0; [cell accessibilityElementAtIndex:f]; f++);

    UIAccessibilityPostNotification(
        UIAccessibilityLayoutChangedNotification, nil);
    NSLog(@"Layout changed after scrollViewDidScroll");
}

根据表的内容,并非所有单元格都可能响应可访问性方法,因此您可以首先使用respondsToSelector查询每个单元格,以避免发送意外消息。

我还会在创建UIAccessibilityLayoutChangedNotification对象的单元格设置器的末尾发布UIAccessibilityElement,否则您将收到日志消息,说明您的元素消失或找不到。

这些变化使滚动的工作时,迭代元素之一与转子,但你可能会得到奇怪的结果,如果用户滚动一个三指手势。这是因为默认情况下,tableViews一次滚动一个屏幕页面,这个页面可能与单元格没有相同的元素边界,而转子选择的单元是半可见的。根据滚动方向和其他UI元素,半可见单元格可能重叠控制转子被混淆。您需要实现分页滚动以控制这种行为。

票数 1
EN

Stack Overflow用户

发布于 2011-05-04 14:05:12

这个问题会影响VoiceOver模式下应用程序的可用性吗?当我在Mac和iOS上玩过iOS时,突出显示框(尤其是在网页视图中)常常与其屏幕上的对象无法匹配。如果这个应用程序在VoiceOver中仍然可用,我会称它为已知的bug,并在有人抱怨时修复它。

毕竟,我认识的大多数盲人都不看高亮框。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5872453

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档