我正在 Instruments Automation 中保存屏幕截图,但该屏幕截图中缺少一些控件。看起来以编程方式添加的控件被“忽略”了。
我该如何解决?
模拟器中的手动截图:(注意黄色方框)
Instruments Automation 中的屏幕截图:
自动化脚本:
var target = UIATarget.localTarget();
target.delay(0.5)
target.captureScreenWithName( "screenshot1.png" );
我在 Xcode(通用,objective-c)中创建了一个新的单 View 应用程序。我在 Storyboard 中添加了一个按钮和一个带有自动布局约束的标签。
我添加了这段代码以编程方式添加黄色按钮:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIButton *b = [[UIButton alloc] init];
b.backgroundColor = [UIColor yellowColor];
[b setTitle:@"Extra" forState:UIControlStateNormal];
[b setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.view addSubview:b];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:b attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTopMargin multiplier:1.0 constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:b attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTrailingMargin multiplier:1.0 constant:0.0]];
[self.view setNeedsUpdateConstraints];
// Correction: - initially I used the line below, but that was wrong
// The problem is not solved with using setNeedsUpdateConstraints.
// [self.view updateConstraints];
}
我使用的是 Xcode 版本 7.1.1 (7B1005),我的操作系统是 El Capitan 10.11.1 (15B42)。我知道它在早期版本中有效,因为我使用 ui-screen-shooter对于我的应用程序的屏幕截图和现在出现的问题,它以前工作过。这不是 ui-screen-shooter 的问题,因为我可以单独使用仪器自动化重现它。
我该怎么办?
编辑:
Storyboard 中的控件与手动创建的控件之间的一个区别可能是对象 ID,您可以在 Storyboard 源中看到它。如果这是问题所在,我可以为手动创建的控件设置 id
吗? (或者一旦从 Storyboard 中读取场景,它就丢失了吗?)
编辑 2:
我获取了 View Controller View 中元素的所有属性(通过 objc/runtime)并比较了两个按钮的属性值。差异很小:(不包括相同的条目)
Button from Storyboard | Manual Button ----------------------------------------------------------------- "_defaultRenderingMode" = 2; | "_defaultRenderingMode" = 1; text = Button; | text = Extra; | (several position values slightly different) | description contains: | "autoresize = RM+BM;" | | backgroundColorSystemColorName = yellowColor;
EDIT 3:
A screenshot of the output of target.logElementTree()
:
EDIT 4:
I added
[UIButton appearance].backgroundColor = [UIColor yellowColor];
所有按钮现在都有黄色背景,但是屏幕截图中没有“额外”按钮。
我主要关注的不是自定义外观。我也试过了
UIButton *b = [UIButton buttonWithType:UIButtonTypeSystem];
所以这个按钮就像典型的蓝色按钮一样。该按钮仍然没有出现在自动化屏幕截图中。
编辑 5:
如果它是相关的:我可以从自动化脚本访问控件并进行点击 - 例如(从另一个应用程序,而不是这个测试代码):
target.frontMostApp().mainWindow().buttons()[25].tap()
点击已处理,因此自动化脚本可以访问控件。
编辑 6:我在 Apple 的错误报告系统中创建了错误报告。如果您可以重现它,那么做同样的事情可能会很好(至少我是这样理解 Apple 错误报告的预期用途的)。
编辑 7:(感谢 quellish 的回答 - 在这里处理我的第一波想法:)我更正了代码中的一个错误 - 我调用了 [self.view updateConstraints];
,但是它应该是 [self.view setNeedsUpdateConstraints];
。然而,这对自动化屏幕截图结果没有影响。
我想知道是否更新了约束并记录了对 updateViewConstraints
和其他一些调用的调用。这是应用加载时的记录方式:
viewDidLoad
viewWillAppear
updateViewConstraints
viewWillLayoutSubviews
viewWillLayoutSubviews
viewDidAppear
因此,当我在 viewDidLoad
中添加按钮和约束并调用 updateViewConstraints
时,我会假设在 viewDidAppear
时所有约束都已解决> 被调用。
我在 viewDidAppear
中使用它做了一个快速测试:(还不确定,这是否是要走的路 - 我对可访问性没有什么经验。)
_extraButton.accessibilityFrame = UIAccessibilityConvertFrameToScreenCoordinates(_extraButton.frame, self.view);
自动化屏幕截图保持白色。
然而,有趣的是,在元素树中,额外按钮的屏幕截图部分显示了正确的位置。所以我假设,自动化选择了正确的位置。
最佳答案
您遇到的问题是由多种因素造成的。如您的问题所述,您的问题是:
- 鉴于您包含的测试项目和自动化脚本,UIAutomation 屏幕截图不会包含您的样式按钮。
在不同的条件下你会看到不同的行为:
当通过 nib 或 Storyboard 实例化按钮时,不会出现问题,只有当按钮被声明并添加到代码中的 View 层次结构时(具体来说,
viewDidLoad
View Controller )。当在早期版本的 iOS(即 iOS 8)中运行时,该按钮确实出现在 UIAutomation 屏幕截图中。
就是说,如果您删除 viewDidLoad
中添加的约束,您将看到样式化的按钮开始出现在屏幕截图中。这应该是一个提示 - 约束是问题的一部分。
当布局引擎解决约束时,它会尝试分批处理尽可能多的工作,合并约束以提高性能。当在 nib 或 Storyboard中描述按钮和约束时,约束引擎将同时获取它们,并且在 View 层次结构的生命周期中更早。因此,可以显着简化布局过程的步骤。
但是,当稍后在 View 层次结构生命周期中添加约束时,需要重新评估约束。将添加的约束视为添加到队列中,布局引擎将在下次队列“满”时重新评估它们。 UIAutomation Hook 到 UIAccessibility API 中来做它的事情 - 可访问性可能不知道或不关心视觉表示的布局发生了什么。视觉表示可能会发生变化,但不会影响可访问性,因此不会影响 UIAutomation 的世界观。
iOS 9 改变了布局过程背后的几个方面,这就是您现在看到这个问题的原因。
您可以采取多种行动:
在 nib 或 Storyboard中构建您的 View 层次结构。这将为您带来最一致的体验,并具有性能和其他优势。
使用辅助功能 API 提示按钮的位置(辅助功能框架)在布局传递后发生了变化。遗憾的是,除非在布局完成之前禁用可访问性、可见性或用户交互,否则您仍然可能会在布局发生时看到 UIAutomation 捕获它。
与其在自动化脚本中任意延迟,不如有效地使用 UIAutomation 超时来等待元素可用。这是 covered in the documentation并且是最佳实践。在布局完成之前使其不可用或无效。
使用这些方法,我能够轻松地让您的示例项目不再重现您所看到的问题。这些解决方案中的部分或全部可能适合您的项目,也可能不适合。
关于ios - Instruments Automation 屏幕截图忽略以编程方式添加的控件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33975321/