无法为自定义UITableViewCell配置语音可访问性

时间:2016-10-21 14:13:54

标签: ios objective-c iphone uitableview uiaccessibility

我们的iPhone应用程序目前支持IOS 8/9/10。我无法支持自定义UITableViewCell的语音可访问性。我已经浏览了以下SO帖子,但没有一个建议有效。我希望可以访问各个组件。

  1. Custom UITableview cell accessibility not working correctly
  2. Custom UITableViewCell trouble with UIAccessibility elements
  3. Accessibility in custom drawn UITableViewCell
  4. https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/iPhoneAccessibility/Making_Application_Accessible/Making_Application_Accessible.html#//apple_ref/doc/uid/TP40008785-CH102-SW10
  5. http://useyourloaf.com/blog/voiceover-accessibility/
  6. 对我来说不幸的是,辅助功能检查员未检测到该单元格。有没有办法说出可访问性来获取表格视图单元格中的各个元素?在设备和模拟器上调试此问题时,我发现XCode调用isAccessibleElement函数。当函数返回NO时,将跳过其余方法。我在XCode上测试IOS 9.3。

    我的自定义表格视图单元格由标签和开关组成,如下所示。

    Custom UITableView Cell with a label and a switch

    标签将添加到内容视图中,而交换机将添加到自定义附件视图中。

    接口定义如下:

    @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
    

1 个答案:

答案 0 :(得分:4)

首先,根据您描述的模式,我不确定您为什么要区分单元格中的不同元素。通常,Apple会将每个单元格保留为单个可访问性元素。设置应用程序中有一个查看具有标签和开关的单元格的预期iOS VO行为的好地方。

如果您仍然认为处理单元格的最佳方法是使它们包含单个元素,那么这实际上是单元格的默认行为 UITableViewCell本身没有可访问性标签时。所以,我已经修改了下面的代码并在我的iOS设备上运行它(运行9.3),它可以按照您的描述运行。

你会注意到一些事情。

  1. 我删除了所有自定义accessibilityElements代码。没有必要。
  2. 我在UITableViewCell子类本身上删除了isAccessibilityElement的覆盖。我们想要默认行为。
  3. 我注释掉将内容视图设置为accessibilityElement - 我们希望它为NO,以便树构建器在其中查找元素。
  4. 我将customAccessoryView的isAccessibilityElement设置为NO,原因与上述相同。一般来说,NO说"继续俯视树"并且YES说"停在这里,就可访问性而言,这是我的叶子。"
  5. 我希望这会有所帮助。再一次,我真的鼓励你在设计辅助功能时模仿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