有没有一种方法可以找出XCUIElement是否具有焦点?

24

我的一个屏幕有多个文本字段,我可以从不同的其他屏幕进入该屏幕。在每种情况下,我都会将一个或另一个文本字段作为第一响应者。我无法编写测试以确定所需的textField是否具有焦点。

当我在控制台中打印textfield时 -

输出:{ TextField 0x131171d40: traits: 146031247360, 聚焦,{{6.0,108.3},{402.0,35.0}},值:​ }

但我找不到任何关于XCUIElement的focus/isFocus属性。

有没有办法实现这个?


XCUIElement 似乎从辅助功能属性中派生一些属性,但不一定公开这些特性。您尝试过使用 selected 属性来查看是否能得到所需的结果吗? - Charles A.
我的文本框的“selected”属性返回false/nil。 - Sandy
有一个属性叫做 hasKeyboardFocus,请看下面我的回答。 - hris.to
5个回答

29

我有点晚参加派对 :) 不过从转储变量XCUIElement可以看出它有一个有趣的属性:

属性名称:hasKeyboardFocus

属性类型:TB,R

因此,您可以按照以下方式检查元素是否具有焦点:

let hasFocus = (yourTextField.value(forKey: "hasKeyboardFocus") as? Bool) ?? false

注意:您可以使用以下扩展程序转储任何NSObject子类的属性变量:

extension NSObject {
    func dumpProperties() {
        var outCount: UInt32 = 0

        let properties = class_copyPropertyList(self.dynamicType, &outCount)
        for index in 0...outCount {
            let property = properties[Int(index)]
            if nil == property {
                continue
            }
            if let propertyName = String.fromCString(property_getName(property)) {
                print("property name: \(propertyName)")
            }
            if let propertyType = String.fromCString(property_getAttributes(property)) {
                print("property type: \(propertyType)")
            }
        }
    }
}

更新:属性转储,Swift 4:

extension NSObject {
    func dumpProperties() {
        var outCount: UInt32 = 0

        let properties = class_copyPropertyList(type(of: self), &outCount)
        for index in 0...outCount {
            guard let property = properties?[Int(index)] else {
                continue
            }
            let propertyName = String(cString: property_getName(property))
            print("property name: \(propertyName)")
            guard let propertyAttributes = property_getAttributes(property) else {
                continue
            }
            let propertyType = String(cString: propertyAttributes)
            print("property type: \(propertyType)")
        }
    }
}

1
太棒了,感谢您回答这个问题! - Patrick
3
精彩的回答!如果你想等待具有焦点的元素,只需使用谓词和期望let focusPredicate = NSPredicate(format: "exists == true && hasKeyboardFocus == true")即可。请注意,翻译保持了原文意思的同时尽可能地通俗易懂,并且没有提供解释或其他内容。 - user3292998
1
太好了!苹果的文档中写道:“XCUIElementAttributes协议,作为XCUIElement的一部分,提供了查询UI元素属性当前状态的附加属性。”该协议有一个“hasFocus”变量,但是当尝试实际使用它时,你会从Xcode收到“XCUIElement没有成员'hasFocus'”的消息。再次感谢! - Jacob Boyd
1
@hris.to 你是如何找到名为“hasKeyboardFocus”的属性的?甚至苹果文档也没有提到它。你能把上面的代码优化到Swift 4及以上吗?在“self.dynamicType”这一行会抛出错误。 - Confused
@Confused:这些引用显示类型以T开头,然后跟随@encode类型(B显然表示“C++布尔值或C99 _Bool”)。在表7-1Property Type String下方显示的R显然表示只读。有趣... - leanne
显示剩余2条评论

13

基于@hris.to的出色回答,我制作了这个小扩展(在Swift 4中也适用)...

extension XCUIElement
{
    func hasFocus() -> Bool {
        let hasKeyboardFocus = (self.value(forKey: "hasKeyboardFocus") as? Bool) ?? false
        return hasKeyboardFocus
    }
}

2
可以像这样定义一个计算属性:var hasFocus: Bool { return ... } - boweidmann
@boweidmann 我不知道我是否做得对,但当没有参数时,我总是更喜欢使用计算属性而不是方法。 ;) - Thomás Pereira

0

我观察到一些情况

XCUIApplication().textFields[{index/identifier}].selected

即使我将光标聚焦在文本字段上,它仍然不返回true,但我可以使用.typeText()输入文本。然而,.enabled正确地返回true,似乎'enabled'值表示UI元素已启用可访问性,您可以与之交互。

这不是一个干净的解决方案,但您可以尝试。

XCUIApplication().textFields.elementMatchingPredicate("predicate")

或者使用 .elementMatchingType() 获取 XCUIElement 并在处理异常情况时编写测试块,使用 guard 语句抛出适当的错误,如果未找到 textField。


2
在这里使用“启用”不会有帮助。启用告诉我们 - 元素是否启用了用户交互。我的任何textField都没有处于禁用状态。你明白我的问题吗?我正在询问如何验证我的textField是否是第一个响应者。 - Sandy
从你的问题中,我读到你的目标是确定Textfield是否有焦点,以便你可以与它交互。如果您想验证UIView的当前第一个响应者是否为您期望的UITextField元素,则可以检查此gist链接(https://gist.github.com/steipete/8737196)。一个不太正规的解决方法是获取第一个响应者UIView标题以与您预期的textField标题匹配,并编写条件测试。 - Sushant

0
我不确定,但也许你要找的是 XCUIElement 上的 selected 属性。试试看吧。

1
没有成功。在我的情况下,它会返回文本字段的 false/nil。 - Sandy

0

UIAccessibility.h中,NSObject有一个通过extension扩展的方法,可在XCUIElement上使用,名为accessibilityElementIsFocused(),但即使该元素的debugDescription明确显示Focused,它似乎也不返回true。还有一些其他相关方法accessibilityElementDidLoseFocus()accessibilityElementDidBecomeFocused(),这些方法似乎是用于被NSObject的子类重写以获取有关Focused状态更改的通知。

经过这番挖掘,我倾向于说我们正在讨论的Focused概念与firstResponder状态不同,这可能是您希望了解的内容。我认为此时焦点表示该元素是某些辅助技术(如VoiceOver)的焦点,基于这些方法的一些注释。

如果您想直接判断项目是否为firstResponder,我认为现在是时候提交错误报告了。

如果有一种直接与软件键盘交互的方法,那么一个hacky的解决方法可能是获取您的UITextFieldXCUIElement,并在使用键盘输入后比较您的UITextField元素的value(您可能需要先输入一个字符然后再按退格键)。话虽如此,我在粗略尝试中无法找到直接获取键盘的方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接