我们的iPhone应用程序目前支持IOS 8/9/10。我无法支持自定义UITableViewCell的语音可访问性。我已经浏览了以下SO帖子,但没有一个建议有效。我希望可以访问各个组件。
对我来说不幸的是,辅助功能检查员未检测到该单元格。有没有办法说出可访问性来获取表格视图单元格中的各个元素?在设备和模拟器上调试此问题时,我发现XCode调用isAccessibleElement
函数。当函数返回NO
时,将跳过其余方法。我在XCode上测试IOS 9.3。
我的自定义表格视图单元格由标签和开关组成,如下所示。
标签将添加到内容视图中,而交换机将添加到自定义附件视图中。
接口定义如下:
@interface MyCustomTableViewCell : UITableViewCell
///Designated initializer
- (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier;
///Property that determines if the switch displayed in the cell is ON or OFF.
@property (nonatomic, assign) BOOL switchIsOn;
///The label to be displayed for the alert
@property (nonatomic, strong) UILabel *alertLabel;
@property (nonatomic, strong) UISwitch *switch;
#pragma mark - Accessibility
// Used for setting up accessibility values. This is used to generate accessibility labels of
// individual elements.
@property (nonatomic, strong) NSString* accessibilityPrefix;
-(void)setAlertHTMLText:(NSString*)title;
@end
下面给出了实现块
@interface MyCustomTableViewCell()
@property (nonatomic, strong) UIView *customAccessoryView;
@property (nonatomic, strong) NSString *alertTextString;
@property (nonatomic, strong) NSMutableArray* accessibleElements;
@end
@implementation MyCustomTableViewCell
- (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier
{
if(self = [super initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:reuseIdentifier]) {
[self configureTableCell];
}
return self;
}
- (void)configureTableCell
{
if (!_accessibleElements) {
_accessibleElements = [[NSMutableArray alloc] init];
}
//Alert label
self.alertLabel = [[self class] makeAlertLabel];
[self.contentView setIsAccessibilityElement:YES];
//
[self.contentView addSubview:self.alertLabel];
// Custom AccessoryView for easy styling.
self.customAccessoryView = [[UIView alloc] initWithFrame:CGRectZero];
[self.customAccessoryView setIsAccessibilityElement:YES];
[self.contentView addSubview:self.customAccessoryView];
//switch
self.switch = [[BAUISwitch alloc] initWithFrame:CGRectZero];
[self.switch addTarget:self action:@selector(switchWasFlipped:) forControlEvents:UIControlEventValueChanged];
[self.switch setIsAccessibilityElement:YES];
[self.switch setAccessibilityTraits:UIAccessibilityTraitButton];
[self.switch setAccessibilityLabel:@""];
[self.switch setAccessibilityHint:@""];
self.switch.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
[self.customAccessoryView addSubview:self.switch];
}
+ (UILabel *)makeAlertLabel
{
UILabel *alertLabel = [[UILabel alloc] initWithFrame:CGRectZero];
alertLabel.backgroundColor = [UIColor clearColor];
alertLabel.HTMLText = @"";
alertLabel.numberOfLines = 0;
alertLabel.lineBreakMode = LINE_BREAK_WORD_WRAP
[alertLabel setIsAccessibilityElement:YES];
return alertLabel;
}
-(void)setAlertHTMLText:(NSString*)title{
_alertTextString = [NSString stringWithString:title];
[self.alertLabel setText:_alertTextString];
}
- (BOOL)isAccessibilityElement {
return NO;
}
// The view encapsulates the following elements for the purposes of
// accessibility.
-(NSArray*) accessibleElements {
if (_accessibleElements && [_accessibleElements count] > 0) {
[_accessibleElements removeAllObjects];
}
// Fetch a new copy as the values may have changed.
_accessibleElements = [[NSMutableArray alloc] init];
UIAccessibilityElement* alertLabelElement =
[[UIAccessibilityElement alloc] initWithAccessibilityContainer:self];
//alertLabelElement.accessibilityFrame = [self convertRect:self.contentView.frame toView:nil];
alertLabelElement.accessibilityLabel = _alertTextString;
alertLabelElement.accessibilityTraits = UIAccessibilityTraitStaticText;
[_accessibleElements addObject:alertLabelElement];
UIAccessibilityElement* switchElement =
[[UIAccessibilityElement alloc] initWithAccessibilityContainer:self];
// switchElement.accessibilityFrame = [self convertRect:self.customAccessoryView.frame toView:nil];
switchElement.accessibilityTraits = UIAccessibilityTraitButton;
// If you want custom values, just override it in the invoking function.
NSMutableString* accessibilityString =
[NSMutableString stringWithString:self.accessibilityPrefix];
[accessibilityString appendString:@" Switch "];
if (self.switchh.isOn) {
[accessibilityString appendString:@"On"];
} else {
[accessibilityString appendString:@"Off"];
}
switchElement.accessibilityLabel = [accessibilityString copy];
[_accessibleElements addObject:switchElement];
}
return _accessibleElements;
}
// In case accessibleElements is not initialized.
- (void) initializeAccessibleElements {
_accessibleElements = [self accessibleElements];
}
- (NSInteger)accessibilityElementCount
{
return [_accessibleElements count]
}
- (id)accessibilityElementAtIndex:(NSInteger)index
{
[self initializeAccessibleElements];
return [_accessibleElements objectAtIndex:index];
}
- (NSInteger)indexOfAccessibilityElement:(id)element
{
[self initializeAccessibleElements];
return [_accessibleElements indexOfObject:element];
}
@end
答案 0 :(得分:4)
首先,根据您描述的模式,我不确定您为什么要区分单元格中的不同元素。通常,Apple会将每个单元格保留为单个可访问性元素。设置应用程序中有一个查看具有标签和开关的单元格的预期iOS VO行为的好地方。
如果您仍然认为处理单元格的最佳方法是使它们包含单个元素,那么这实际上是单元格的默认行为当 UITableViewCell本身没有可访问性标签时。所以,我已经修改了下面的代码并在我的iOS设备上运行它(运行9.3),它可以按照您的描述运行。
你会注意到一些事情。
我希望这会有所帮助。再一次,我真的鼓励你在设计辅助功能时模仿Apple的VO模式。我认为您确保自己的应用可以访问非常棒!
#import "MyCustomTableViewCell.h"
@interface MyCustomTableViewCell()
@property (nonatomic, strong) UIView *customAccessoryView;
@property (nonatomic, strong) NSString *alertTextString;
@property (nonatomic, strong) NSMutableArray* accessibleElements;
@end
@implementation MyCustomTableViewCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
if(self = [super initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:reuseIdentifier]) {
[self configureTableCell];
}
return self;
}
// just added this here to get the cell to lay out for myself
- (void)layoutSubviews {
[super layoutSubviews];
const CGFloat margin = 8;
CGRect b = self.bounds;
CGSize labelSize = [self.alertLabel sizeThatFits:b.size];
CGFloat maxX = CGRectGetMaxX(b);
self.alertLabel.frame = CGRectMake(margin, margin, labelSize.width, labelSize.height);
CGSize switchSize = [self.mySwitch sizeThatFits:b.size];
self.customAccessoryView.frame = CGRectMake(maxX - switchSize.width - margin * 2, b.origin.y + margin, switchSize.width + margin * 2, switchSize.height);
self.mySwitch.frame = CGRectMake(margin, 0, switchSize.width, switchSize.height);
}
- (void)configureTableCell
{
//Alert label
self.alertLabel = [[self class] makeAlertLabel];
//[self.contentView setIsAccessibilityElement:YES];
//
[self.contentView addSubview:self.alertLabel];
// Custom AccessoryView for easy styling.
self.customAccessoryView = [[UIView alloc] initWithFrame:CGRectZero];
[self.customAccessoryView setIsAccessibilityElement:NO]; // Setting this to NO tells the the hierarchy builder to look inside
[self.contentView addSubview:self.customAccessoryView];
self.customAccessoryView.backgroundColor = [UIColor purpleColor];
//switch
self.mySwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
//[self.mySwitch addTarget:self action:@selector(switchWasFlipped:) forControlEvents:UIControlEventValueChanged];
[self.mySwitch setIsAccessibilityElement:YES]; // This is default behavior
[self.mySwitch setAccessibilityTraits:UIAccessibilityTraitButton]; // No tsure why this is here
[self.mySwitch setAccessibilityLabel:@"my swich"];
[self.mySwitch setAccessibilityHint:@"Tap to do something."];
self.mySwitch.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
[self.customAccessoryView addSubview:self.mySwitch];
}
+ (UILabel *)makeAlertLabel
{
UILabel *alertLabel = [[UILabel alloc] initWithFrame:CGRectZero];
alertLabel.backgroundColor = [UIColor clearColor];
alertLabel.text = @"";
alertLabel.numberOfLines = 0;
[alertLabel setIsAccessibilityElement:YES];
return alertLabel;
}
-(void)setAlertHTMLText:(NSString*)title{
_alertTextString = [NSString stringWithString:title];
[self.alertLabel setText:_alertTextString];
}
@end