【问题标题】:viewDidLayoutSubviews no longer called when popping top view with UINavigationController使用 UINavigationController 弹出顶视图时不再调用 viewDidLayoutSubviews
【发布时间】:2017-02-08 09:06:45
【问题描述】:

iOS 10,不断打破的礼物,似乎改变了另一种行为。

假设两个 UIViewController 被推送到一个 UINavigationController。

在 iOS 8/9 上,调用 navigationController?.popViewController(animated: true) 来弹出顶部 UIViewController(比如 VC2)会导致底部视图控制器(比如 VC1)上的 viewDidLayoutSubviews 被调用。

我们依靠它来刷新 VC1。有时 VC2 会向 VC1 添加子视图(通过数据模型),这需要在弹出回 VC1 时反映出来。

需要准确的帧信息。我们不能使用viewWillAppear,因为frame data is wrong on iOS 9viewDidAppear 的问题是在最初看到视图和调整之间存在短暂的故障。

现在 VC1 的 viewDidLayoutSubviews 在弹出 VC2 时不会被调用。

1) 这是viewDidLayoutSubviews 无法被调用的错误吗?

2) 使用 UINavigationController 弹出时刷新视图控制器的正确方法是什么?

【问题讨论】:

  • 我假设 viewDidLayoutSubviews 在某个时候被调用。是和其他控制器(VC2)一起调用吗?
  • @LeoNatan 是的,它在 VC1 第一次出现时被调用
  • 实际上听起来是可以接受的行为。如果你更新viewDidLayoutSubviews中的数据源,那就不好了。
  • @LeoNatan 不,我们不会更新 viewDidLayoutSubviews 中的数据源。 VC2中修改了数据源,但VC1应该反映新数据(这会导致出现新的子视图)。
  • @Crashalot 那么我在回答中的内容是正确的。您应该更新viewWillAppear 中的数据并添加/更新任何新视图。新视图应根据视图控制器当时的视图大小进行设置。 viewDidLayoutSubviews 可以正常使用来调整子视图的框架。

标签: ios swift uiviewcontroller uinavigationcontroller viewdidlayoutsubviews


【解决方案1】:

依赖viewDidLayoutSubviews 从来都不是正确的解决方案。 UIViewController 提供 viewWillAppear:viewDidAppear: 用于此类用途。当 VC2 从导航控制器弹出时,这两个方法将在 VC1 上调用,让您知道它将会或现在再次可见。

viewDidLayoutSubviews 只能用于调整视图框架和布局。

viewWill|DidAppear: 应该用于处理视图控制器最初或再次变为可见。在您的情况下,您应该使用它来更新数据并根据需要添加/更新视图。这些新视图应根据视图控制器的当前帧进行设置。它们将根据需要在您的viewDidLayoutSubviews 实现中进行调整。

【讨论】:

  • 很抱歉应该澄清帧信息是必需的,但似乎viewWillAppear 不包含正确的帧数据:stackoverflow.com/questions/32662851/…viewDidAppear 的问题是在最初看到视图和调整之间存在短暂的故障。
  • viewDidLayoutSubviews 有时更适合放置特别需要布局视图的代码。例如,在viewWillAppear 中,层次结构通常不完整且尚未准备好。 viewDidAppear 为时已晚,因为它发生在动画之后。在这种情况下,刷新一个数据源确实不是这个地方。
  • @LeoNatan 正是我们的评估。那么有什么建议吗?另外(1)这是iOS 10上的错误吗? (2) 还是从现在开始这是预期的行为?
  • @LeoNatan 我们不反对。我从来没有说过要在viewWillAppear 中布置视图。我说调整框架属于viewDidLayoutSubviews。但这不是问题。
  • @Crashalot One 不知道。如果您认为这是一个问题,请打开错误报告。 viewDidLayoutSubviews 用于布局视图,而不是更新数据。
【解决方案2】:

我会补充 rmaddy 的回答。您需要将执行布局和更新数据分离。如果您的流程需要在视图即将出现时更新数据,您应该在viewWillAppear: 中更新控制器的视图支持数据,重新加载您的视图,然后使用setNeedsLayout 将视图标记为需要布局。这将导致系统在控制器的视图上执行布局,并触发布局。这样,您可以确保在视图准备好后执行布局,而不是之前(viewWillAppear: 中经常出现这种情况。

【讨论】:

  • 在明确目标是添加新视图之前,这正是我在回答中的意思。我在回答中概括了这一点,简单地说应该使用viewWillAppear 来处理变得可见的视图。在这种情况下,该处理是添加新视图和刷新数据。
  • @rmaddy 这常常令人困惑。我习惯了人们推荐在视图上执行布局的viewWillAppear 路线,这通常是不正确的。首先,我是这样读你的答案的。
  • 你需要打电话给layoutIfNeededsetNeedsLayout吗?
  • 没有。系统会在显示之前知道它需要布局。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多