Я пытаюсь поместить пользовательский вид в UITableViewCell
, который, конечно, живет в пределах UITableView
. Я хочу сделать этот пользовательский вид доступным, поэтому мне нужно сделать его UIAccessibilityContainer
(так как он содержит несколько визуальных элементов, которые не реализованы как их собственные UIViews).
Когда я делаю это, расположение элементов запутывается всякий раз, когда таблица прокручивается. При перемещении по элементам с помощью VoiceOver он автоматически прокручивает таблицу, пытаясь отцентрировать выбранный элемент на экране, но затем контур того, где VoiceOver считает, что элемент больше не совпадает с тем, где он находится визуально.
Обратите внимание, что на снимке экрана инспектор говорит: «Строка 4, элемент 2», но выделенная область - это случайное место в строке 7, поскольку это происходит там, где строка 4 находилась до автоматической прокрутки таблицы.
Я думаю, что мне, возможно, придется использовать UIAccessibilityPostNotification()
, чтобы опубликовать изменение макета, когда прокручивается табличное представление, но мне не нужно это делать, когда я не использую UIAccessibilityContainer
, и мне кажется, что я не должен был это делать, и что система должна обрабатывать это для меня - но тот факт, что UIAccessibilityElement
должен иметь его accessibilityFrame
, установленный в экранных координатах, кажется, бросает складки на вещи. (Дополнительный вопрос: почему, черт возьми, API-интерфейс спроектирован таким образом? Почему бы не определить фрейм относительно контейнера элемента или что-то в этом роде? Арг.)
Вот реализация пользовательского представления на случай, если здесь есть что-то, что вызывает проблему. Для полного проекта (Xcode 4), нажмите здесь .
@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
Edit : я должен заметить, что я пробовал варианты, которые обновляют accessibilityFrame
элемента в -indexOfAccessibilityElement:
и -accessibilityElementAtIndex:
с идеей, что VoiceOver будет запрашивать элемент каким-либо образом, когда ему это нужно, и это быть хорошим временем, чтобы обновить вещи. Однако это тоже не работает. Я надеялся, что VoiceOver автоматически запросит что-то перерисовать, но это тоже не работает. (Идея поместить код установки местоположения в -drawRect:
исходит из того, что я помню, когда видел на WWDC об этом, но мне было неясно, было ли это «наилучшей практикой» или просто оказалось удобным.)