【问题标题】:How to turn off AutoLayout for a view hierarchy programmatically?如何以编程方式关闭视图层次结构的自动布局?
【发布时间】:2015-05-21 04:47:20
【问题描述】:

我创建了一个单独的框架来容纳我的视图层次结构,应该启用自动布局。为此,我取消了 Interface Builder 中的“使用自动布局”复选框(在故事板上)。

我将以下操作添加到此基本视图中的按钮,以测试视图层次结构(视图 + 按钮)上没有生成任何约束:

    @IBAction func buttonPressed(sender:AnyObject?){
    println(self.view.constraints)
    println(self.view.subviews[0].constraints)
}

然后我将上面的框架导入到一个新的 Cocoa 应用程序中,该应用程序启用了 AutoLayout,并在容器视图控制器中重新使用上面框架中的视图控制器。按下按钮时,结果如下:

[]
[<NSContentSizeLayoutConstraint:0x6080000a7da0 H:
[NSButton:0x600000140e70'Button'(46)] Hug:250 CompressionResistance:750>,
<NSContentSizeLayoutConstraint:0x6080000ad6e0
V:NSButton:0x600000140e70'Button'(21)] Hug:250 CompressionResistance:750>]

问题:

  1. 以上是否意味着我的按钮以某种方式受到了一些约束?
  2. 是他们在视图层次结构中关闭 AutoLayout 的另一种(更编程的方式)吗?在这种情况下,除了关闭约束之外,我不使用情节提要。

更多信息:

translatesAutoResizingMasksIntoConstraints 对于视图和按钮都设置为 false - 为了安全起见。

我也尝试过运行 Instruments/AutoLayout,但是当我的程序启动时它会崩溃。崩溃报告中的堆栈跟踪显示它在崩溃时正忙于与 AutoLayout 相关的调用!

编辑

我想在我的视图层次结构的一部分中禁用自动布局,只是为了在滚动具有复杂布局的文档时获得性能优势。

我的 scrollView 在类似于 tableView 的控件上执行滚动(它是一个电子表格网格)。我的方法是在您向右滚动时从左侧移动(又名重新布局)单元格等...我发现当我滚动得非常快时会出现滞后效应(表现为角落的闪烁/闪烁)屏幕),细胞无法足够快地移动。他们当然会在 500 毫秒到 1000 毫秒左右之后赶上,但它看起来并没有想象中那么好。

使用 Instruments(时间分析器)我还可以看到大部分繁忙时间都被“布局和显示”占用,布局与显示差不多。我还在没有将内容加载到单元格中的情况下进行了测试,以了解布局是否发生得不够快(事实并非如此)。

更有趣的是,看看 Instruments (AutoLayout),我当然可以看到它在滚动期间非常忙于处理约束,尽管我不能说这是否一定是坏的。

我的想法是,对于像这样的复杂(按移动部件的数量)视图/控件,AutoLayout 在数学上解决约束集问题的时间可能比我直接告诉它新框架的时间要长是直接的。

【问题讨论】:

  • 您是否尝试过将您的网格视图(据我了解,它本身不使用自动布局)放入一个窗口中,而您所控制的任何东西都没有使用自动布局?您是否发现任何基线场景可以提供可接受的性能来比较自动布局案例?您是否在利用响应式滚动并保留位于视图的 preparedContentRect 而不仅仅是其 visibleRect 内的单元格?
  • 网格的初始实现是使用 AutoLayout。今天大部分时间都在没有自动布局的情况下重新实现。它看起来不像非自动布局方式表现得更好,我需要在窗口的其余部分自动布局 - 死胡同,掉头,继续!
  • 我的布局中确实允许过度绘制(几列和几行 - 试图节省内存)但它与 preparedContentRect 无论如何都不匹配。我怀疑可能发生的事情是 AppKit 在我的基本过度绘制之外进行过度绘制,因此在物理上准备了一些空白画布,以便在我滚动时愉快地向我展示 - 只有在之后它才会重新布置这些视图。
  • @KenThomases 您能否结合使用preparedContentRect(使您的透支与AppKit 期望保持一致)和adjustScroll(以“以某种方式”在尝试滚动超出透支时减慢速度)?
  • 我不确定你会如何安排使用-adjustScroll: 来减慢滚动速度。如果您的视图不能或不想准备 AppKit 想要透支的内容,请覆盖 -prepareContentInRect:(与 -preparedContentRect 不同)。您可以将传递的矩形调整为super,这让 AppKit 知道您实际准备了多少。如果您连续两次通过同一个矩形,AppKit 会收到消息并停止尝试扩展过度绘制区域(直到用户再次滚动)。

标签: storyboard autolayout xib nsview nsscrollview


【解决方案1】:

每个窗口启用或禁用自动布局,而不是视图层次结构的部分。如果窗口中的任何内容使用自动布局,那么整个窗口都会这样做。也就是说,如果有任何东西为窗口层次结构中的任何视图添加或激活约束,或者任何视图的类覆盖 +requiresConstraintBasedLayout 以返回 true,则窗口将使用自动布局。

请注意,系统视图甚至主题框架视图(绘制标题栏的内容)都可以在您不知情的情况下使用自动布局。即使您窗口中的视图在当前版本的操作系统中没有使用自动布局,它们也可以在未来的任何版本中更改为这样做。

所以:不,您不能确定禁用自动布局。

translatesAutoResizingMasksIntoConstraints 设置为 false 并不能避免开启自动布局。这只是意味着如果自动布局 is (通过其他方式)打开,这些视图的布局将不正确(因为它们没有从其他任何地方获得约束)。通常,将translatesAutoResizingMasksIntoConstraints 设置为 false 只能由选择in 自动布局的代码完成。

translatesAutoResizingMasksIntoConstraints 默认为 true 允许系统透明地启用应用程序中的窗口中的自动布局,这些应用程序并非旨在使用自动布局而不破坏其行为。

您如何确定自动布局与滚动时的性能问题有关?


更新:

减轻网格视图的自动布局对性能造成的任何影响的一种可能方法是像您一样关闭单元格视图的translatesAutoResizingMasksIntoConstraints(正如我所说的那样是个坏主意),然后手动将它们的框架设置为覆盖-layout。我认为这是合法的。

您可能还会在将它们添加到它们的超级视图时设置它们的框架,但这还不够。如果您不在 -layout 覆盖中布置它们,自动布局可能会将它们的框架归零。

【讨论】:

  • 谢谢。 (1)我能否澄清每个窗口或每个笔尖/故事板启用/禁用它 - 我已经看到后者在 SO 中提到,因此是我的方法。我确实想在窗口的 res 中使用 AutoLayout,并希望在禁用 AutoLayout 的单独故事板中包含“问题子项”。 (2) 我已经通过编辑我的原始问题详细说明了您非常相关的结束问题。
  • 在设计时,您可以启用或禁用 NIB 或情节提要的自动布局。为此,它不是每个窗口。例如,一个 NIB 可以包含多个窗口或仅包含一个视图层次结构而没有窗口。但是,在运行时,如我所描述的,为窗口启用或禁用自动布局。因此,如果您有一个不使用自动布局的视图 NIB,但您加载它并将其视图添加到使用自动布局的窗口中,则该窗口仍对其中的所有内容使用自动布局。
  • 我已经更新了我的答案,提出了一个额外的建议。
  • 你能在主线程之外处理你上面提到的“非自动布局”布局吗?这可以进一步提升性能。
  • 我对此表示怀疑。您不应该从后台线程操作视图层次结构。即使它有效,也只是因为 Cocoa 正在同步到引擎盖下的主线程,所以你会失去任何优势。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-24
  • 1970-01-01
  • 2023-04-03
  • 2013-11-16
  • 2020-10-21
  • 1970-01-01
相关资源
最近更新 更多