简体   繁体   English

无法设置 UISegmentedControl 的段的 accessibilityIdentifier

[英]Unable to set accessibilityIdentifier of UISegmentedControl's segments

I found out, that even though I could set accessibilityLabel of UISegmentedControl 's segment (see: How do I set the accesibility label for a particular segment of a UISegmentedControl? ), I couldn't set accessibilityIdentifier , which was equally important for my project.我发现,即使我可以设置UISegmentedControl段的accessibilityLabel (请参阅: 如何为 UISegmentedControl 的特定段设置可访问性 label? ),我无法设置accessibilityIdentifier ,这对我的项目同样重要. I need to target a segment irrespective of its text and accessibilityLabel for automation purposes.出于自动化目的,我需要定位一个段,而不管其文本和accessibilityLabel是什么。

For example, the code:例如,代码:

NSString *name = [NSString stringWithFormat:@"Item %li", (long)idx];
segment.accessibilityIdentifier = name;
NSLog(@"ID: %@", segment.accessibilityIdentifier);

results in:结果是:

ID: (null)

No exceptions are thrown.没有异常被抛出。

Does anybody have insight into why accessibilityLabel is implemented, but not accessibilityIdentifier ?是否有人了解为什么实施accessibilityLabel而不是accessibilityIdentifier

I got around this issue by writing a Swift extension for XCUIElement that added a new method tap(at: UInt) . 通过为XCUIElement编写Swift扩展来解决此问题,该扩展添加了新方法tap(at: UInt) This method gets the buttons query of the element and sort the results based on their x position. 此方法获取元素的buttons查询,并根据其x位置对结果进行排序。 This allows us to specify which segment of the UISegmentedControl we want to tap rather than relying on the button text. 这使我们可以指定要点击UISegmentedControl哪个部分,而不是依赖按钮文本。

extension XCUIElement {
    func tap(at index: UInt) {
        guard buttons.count > 0 else { return }
        var segments = (0..<buttons.count).map { buttons.element(boundBy: $0) }
        segments.sort { $0.0.frame.origin.x < $0.1.frame.origin.x }
        segments[Int(index)].tap()
    }
}

I had tested the following code with Xcode 5.1.1 and iOS Simulator 7.1: 我已经使用Xcode 5.1.1和iOS Simulator 7.1测试了以下代码:

UISegmentedControl *contol = [[UISegmentedControl alloc] initWithItems:
                              @[@"0", @"1"]];
[self.view addSubview:contol];

UIView *segment = [[contol subviews] firstObject];
segment.accessibilityIdentifier = @"Item 0";
NSLog(@"ID: %@", segment.accessibilityIdentifier);

it didn't work for iPhone Retina (3.5-inch) and iPhone Retina (4-inch) ie result was: 它不适用于iPhone Retina (3.5-inch)iPhone Retina (4-inch)即结果是:

ID: (null)

but it worked for iPhone Retina (4-inch 64-bit) ie result was: 但它适用于iPhone Retina (4-inch 64-bit)即结果为:

ID: Item 0

Then I've replaced @[@"0", @"1"] with @[@"", @""] in UISegmentedControl initialization and the code worked for all mentioned platforms. 然后,我在UISegmentedControl初始化中将@[@"0", @"1"]替换为@[@"", @""] ,该代码适用于所有提到的平台。

It appears, both accessibilityIdentifier and accessibilityLabel are implemented, but somehow the initial values of UISegmentedControl interfere with accessibilityIdentifier s of its segments. 看来, accessibilityIdentifieraccessibilityLabel均已实现,但UISegmentedControl的初始值会干扰其段的accessibilityIdentifier

I implemented this workaround and got automation to work (with KIF). 我实现了此解决方法,并实现了自动化(使用KIF)。

Code is in Swift, works for me with Xcode 6.1.1, iOS 8 SDK 代码在Swift中,适用于Xcode 6.1.1,iOS 8 SDK

for index in 0..<segmentedControl.numberOfSegments {
    let identifierView = UIView()
    identifierView.accessibilityIdentifier = "Item \(index)"
    (segmentedControl.subviews[index] as UIView).addSubview(identifierView)
}

I only had images, without any labels, so I used the code below. 我只有图像,没有任何标签,因此我使用了下面的代码。 I found the indexes didn't correspond to the order on screen, so I keyed off of the initial accessibilityLabel values, which were the names of the images I specified in Interface Builder. 我发现索引与屏幕上的顺序不符,所以我键入了最初的accessibilityLabel值,这些值是我在Interface Builder中指定的图像的名称。

override func viewDidLoad() {
    super.viewDidLoad()

    for segment in segmentedControl.subviews {
        switch segment.accessibilityLabel {
        case .Some("First Image"):
            segment.accessibilityLabel = "Description of first item"
            break

        case .Some("Second Image"):
            segment.accessibilityLabel = "Description of second item"
            break

        default:
            NSLog("Unknown accessibility label: \(segment.accessibilityLabel)")
            break
        }
    }
}

I ran into this. 我遇到了这个。 Some of the previous answers didn't seem to address the accessibilityIdentifier at all. 先前的某些答案似乎根本没有解决accessibilityIdentifier。 I did try Jawwad's approach of accessing the segments and adding a new UIView and setting the accessibilityIdentifier on that. 我确实尝试了Jawwad访问这些段并添加新的UIView并在其上设置accessibilityIdentifier的方法。 However, I'm using EarlGrey for UI Testing and unfortunately, when it tried to tap on that view, it didn't work. 但是,我正在使用EarlGrey进行UI测试,但是不幸的是,当它尝试点击该视图时,它不起作用。 However, based on this I did the following variation which DID work. 但是,基于此,我做了以下DID工作的变体。

The trick is to enumerate the segments (as per Jawwad) and then for each, find the UIImageView subview and set its accessibilityID. 技巧是枚举段(按照Jawwad的方法),然后为每个段找到UIImageView子视图并设置其accessibilityID。 This works for lookup and interaction. 这适用于查找和交互。

let ids = ["Identifier1", "Identifier2"]

for index in 0..<segmentedControl.numberOfSegments {
    if let view = p.subviews[index] as? UIView {
        for v in view.subviews {
            // Setting the ID twice would cause EarlGrey tests to fail
            if let iv = v as? UIImageView, iv.accessibilityIdentifier == nil {
                iv.accessibilityIdentifier = ids[index]
                break
            }
        }
    }
}

Here is an example of looping through the views to set the accessibilityIdentifier by referencing the segment title. 这是一个通过引用片段标题循环遍历视图以设置accessibilityIdentifier的示例。 Unfortunately when you set the identifier it doesn't persist. 不幸的是,当您设置标识符时,它不会持续存在。 UISegment s must be doing some tricky overriding. UISegment必须进行一些棘手的覆盖。 Still at a loss for how to get this to work. 对于如何使它起作用仍然不知所措。

extension UISegmentedControl {

    /// Sets accessibility for segment buttons
    func setAccessibilityIdentifier(_ accessibilityIdentifier: String, for segmentTitle: String) {

        guard let segment = subviews.first(where: {
            $0.subviews.contains(where: { ($0 as? UILabel)?.text == Optional(segmentTitle) })
        }) else { return }

        segment.accessibilityIdentifier = accessibilityIdentifier
    }

}

I was able to work around the issue by overriding UIView's NSArray *accessibilityElements property, and adding accessibilityIdentifier to each of the returned UISegment.我能够通过覆盖 UIView 的 NSArray *accessibilityElements 属性并将 accessibilityIdentifier 添加到每个返回的 UISegment 来解决这个问题。

- (NSArray *)accessibilityElements {
    NSArray *elements = [super accessibilityElements];
    [elements enumerateObjectsUsingBlock:^(UIView *obj, NSUInteger idx, BOOL *stop) {
        obj.accessibilityIdentifier = self.identifiers[idx].accessibilityIdentifier;
    }];
    return elements;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM