ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
以下主题描述了收集和组织有关布局的信息的技术,以及可能遇到的一些令人惊讶的行为的描述。 不需要在每个布局上使用这些技术,但它们可以帮助您解决最困难的问题。 ## 第一节 理解日志 有关视图的信息可以打印到控制台,因为存在不可满足的布局,或者因为您使用[constraintsAffectingLayoutForAxis:](https://developer.apple.com/documentation/uikit/uiview/1622432-constraintsaffectinglayoutforaxi) 或 [constraintsAffectingLayoutForOrientation:debugging](https://developer.apple.com/documentation/appkit/nsview/1525968-constraintsaffectinglayout) 方法显式打印了约束。 无论哪种方式,您都可以在这些日志中找到许多有用的信息。 以下是不可满足的布局错误的示例输出: ~~~ 2015-08-26 14:27:54.790 Auto Layout Cookbook[10040:1906606] Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) ( "<NSLayoutConstraint:0x7a87b000 H:[UILabel:0x7a8724b0'Name'(>=400)]>", "<NSLayoutConstraint:0x7a895e30 UILabel:0x7a8724b0'Name'.leading == UIView:0x7a887ee0.leadingMargin>", "<NSLayoutConstraint:0x7a886d20 H:[UILabel:0x7a8724b0'Name']-(NSSpace(8))-[UITextField:0x7a88cff0]>", "<NSLayoutConstraint:0x7a87b2e0 UITextField:0x7a88cff0.trailing == UIView:0x7a887ee0.trailingMargin>", "<NSLayoutConstraint:0x7ac7c430 'UIView-Encapsulated-Layout-Width' H:[UIView:0x7a887ee0(320)]>" ) Will attempt to recover by breaking constraint <NSLayoutConstraint:0x7a87b000 H:[UILabel:0x7a8724b0'Name'(>=400)]> Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful. ~~~ 此错误消息显示五个冲突的约束。 并非所有这些约束都可以同时成立。 您需要删除一个,或将其转换为可选约束。 幸运的是,视图层次结构相对简单。 您有一个包含标签和文本字段的父视图。 冲突的约束设置以下关系: 1. The label’s width is greater than or equal to 400 points. 2. The label’s leading edge is equal to the superview’s leading margin. 3. There is an 8-point space between the label and the text field. 4. The text field’s trailing edge is equal to the superview’s trailing margin. 5. The superview’s width is set to 320 points. 系统尝试通过破坏标签的宽度来恢复。 > 注意 > 使用可视格式语言将约束写入控制台。 即使您从未使用可视格式语言来创建自己的约束,您也必须能够阅读并理解它以有效地调试自动布局问题。 有关更多信息,请参阅[可视格式语言](https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/VisualFormatLanguage.html#//apple_ref/doc/uid/TP40010853-CH27-SW1)。 在这些约束中,最后一个是由系统创建的。 你无法改变它。 此外,它与第一个约束产生明显的冲突。 如果你的superview只有320点宽,你永远不会有400点宽的标签。 幸运的是,您不必摆脱第一个约束。 如果将其优先级降至999,系统仍会尝试尽可能接近地提供所选宽度,同时仍满足其他约束。 基于视图的自动调整遮罩的约束(例如,在 [translatesAutoresizingMaskIntoConstraints](https://developer.apple.com/documentation/uikit/uiview/1622572-translatesautoresizingmaskintoco) 为 YES 时创建的约束)具有有关遮罩的其他信息。 在约束的地址之后,日志字符串显示h =后跟三个字符,v =后跟三个字符。 A - (连字符)字符表示固定值,而&(和号)表示灵活值。 对于水平遮罩(h =),三个字符表示左边距,宽边和右边距。 对于垂直遮罩(v =),它们表示上边距,高度和下边距。 例如,日志消息: ~~~ <NSAutoresizingMaskLayoutConstraint:0x7ff28252e480 h=--& v=--& H:[UIView:0x7ff282617cc0(50)]>" ~~~ 此消息包含以下部分: * NSAutoresizingMaskLayoutConstraint:0x7ff28252e480:约束的类和地址。 在此示例中,该类告诉您它基于视图的自动调整遮罩。 * h=--& v=—&:视图的自动调整遮罩。 这是默认遮罩。 水平方向,它具有固定的左边距,固定的宽度和灵活的右边距。 它具有固定的上边距,固定的高度和灵活的下边距。 换句话说,当superview的大小发生变化时,视图的左上角和大小保持不变。 * H:[UIView:0x7ff282617cc0(50)]:约束的可视格式语言描述。 在此示例中,它定义了一个具有50个点的恒定宽度的视图。 此描述还包含受约束影响的任何视图的类和地址。 ## 第二节 将标识符添加到日志中 虽然前面的示例相对容易理解,但较长的约束列表很快就会变得难以理解。 通过为每个视图和约束提供有意义的标识符,可以使日志更易于阅读。 如果视图具有明显的文本组件,Xcode将其用作标识符。 例如,Xcode使用标签的文本,按钮的标题或文本字段的占位符来标识这些视图。 否则,在Identity检查器中设置视图的Xcode特定标签。 Interface Builder在其整个界面中使用这些标识符。 其中许多也显示在控制台日志中。 对于约束,可以通过编程或使用属性检查器来设置它们的标识符属性。自动布局然后在将信息打印到控制台时使用这些标识符。 例如,这里有与标识符集合相同的无法满足的约束错误: ~~~ 2015-08-26 14:29:32.870 Auto Layout Cookbook[10208:1918826] Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) ( "<NSLayoutConstraint:0x7b58bac0 'Label Leading' UILabel:0x7b58b040'Name'.leading == UIView:0x7b590790.leadingMargin>", "<NSLayoutConstraint:0x7b56d020 'Label Width' H:[UILabel:0x7b58b040'Name'(>=400)]>", "<NSLayoutConstraint:0x7b58baf0 'Space Between Controls' H:[UILabel:0x7b58b040'Name']-(NSSpace(8))-[UITextField:0x7b589490]>", "<NSLayoutConstraint:0x7b51cb10 'Text Field Trailing' UITextField:0x7b589490.trailing == UIView:0x7b590790.trailingMargin>", "<NSLayoutConstraint:0x7b0758c0 'UIView-Encapsulated-Layout-Width' H:[UIView:0x7b590790(320)]>" ) Will attempt to recover by breaking constraint <NSLayoutConstraint:0x7b56d020 'Label Width' H:[UILabel:0x7b58b040'Name'(>=400)]> Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful. ~~~ 如您所见,这些标识符允许您快速轻松地识别日志中的约束。 ## 第三节 可视化视图和约束 Xcode提供的工具可帮助您可视化视图层次结构中的视图和约束。 要在模拟器中查看视图: 1. 在模拟器中运行应用程序。 2. 切换回Xcode。 3. 选择“Debug > View Debugging > Show Alignment Rectangles”。 此设置概述了视图的边缘。 ![](https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/Art/Show_Alignment_Rectangles_2x.png =451x247) 对齐矩形是自动布局使用的边。 启用此选项可以快速找到意外调整大小的任何对齐矩形。 如果您需要更多信息,请在Xcode调试栏中单击Debug View Hierarchy按钮(![](https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/Art/Screen%20Shot%202015-08-26%20at%2011.35.43%20AM.png) )。然后Xcode显示一个交互式视图调试器,为您提供了许多用于探索视图层次结构并与之交互的工具。 调试自动布局问题时,“显示剪切的内容(Show clipped content)”和“显示约束(Show constraints)”选项特别有用。 ![](https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/Art/Debug_View_Hierarchy_2x.png =681x232) 启用“显示剪切的内容”选项会显示可能意外放置在屏幕外的视图的位置。 启用“显示约束”选项会显示影响当前所选视图的所有约束。 当事情开始表现奇怪时,这两个选项都提供了快速的健全性检查。 有关更多信息,请参阅 [Debug Area Help](http://help.apple.com/xcode)。 ## 第四节 了解边缘情况 以下是一些可能导致自动布局以意外方式运行的边缘情况: * 自动布局根据对齐矩形而不是框架来定位视图。 大多数情况下,这些值是相同的。 但是,某些视图可能会设置自定义对齐矩形以从布局计算中排除部分视图(例如,徽章)。 有关更多信息,请参阅 [UIView类参考中](https://developer.apple.com/documentation/uikit/uiview) 的使用自动布局对齐视图。 * 在 iOS 中,您可以使用视图的 transform 属性来调整视图大小,旋转或移动视图; 但是,这些转换不会以任何方式影响自动布局的计算。 自动布局根据其未转换的帧计算视图的对齐矩形。 * 视图可以显示其边界之外的内容。 大多数情况下,视图行为正常并将其内容限制在其范围内。 但是,出于性能原因,图形引擎不强制执行此操作。 这意味着可以以与其帧不同的大小绘制视图(尤其是具有自定义绘图的视图)。 您可以通过将视图的 [clipsToBounds](https://developer.apple.com/documentation/uikit/uiview/1622415-clipstobounds) 属性设置为 YES 或通过验证视图框架的大小来识别这些错误。 * 仅当所有视图以其内部内容高度显示时,[NSLayoutAttributeBaseline](https://developer.apple.com/documentation/appkit/nslayoutattribute/nslayoutattributebaseline),[NSLayoutAttributeFirstBaseline](https://developer.apple.com/documentation/appkit/nslayoutattribute/nslayoutattributefirstbaseline) 和 [NSLayoutAttributeLastBaseline](https://developer.apple.com/documentation/appkit/nslayoutconstraint/attribute/lastbaseline) 属性才能正确对齐文本。 如果其中一个视图垂直拉伸或收缩,则其文本可能显示在错误的位置。 * 约束优先级在整个视图层次结构中充当全局属性。 您通常可以通过在堆栈视图,布局指南或虚拟视图中对视图进行分组来简化布局; 但是,这种方法并没有封装所包含的视图的优先级。 自动布局继续将组内的优先级与组外的优先级(甚至是其他组内的优先级)进行比较。 * 宽高比约束允许水平和垂直约束进行交互。 通常,水平和垂直布局是分开计算的。 但是,如果约束视图相对于宽度的高度,则会在垂直和水平约束之间创建连接:它们现在可以相互影响并发生冲突。 这些交互极大地增加了布局的复杂性,并可能导致布局的不相关部分之间出现意外冲突。 >原文地址 >[Debugging Tricks and Tips](https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/DebuggingTricksandTips.html#//apple_ref/doc/uid/TP40010853-CH21-SW1)