【问题标题】:topLayoutGuide applied after viewWillAppear在 viewWillAppear 之后应用 topLayoutGuide
【发布时间】:2017-10-13 07:09:19
【问题描述】:

我有一个问题,UIViewController(来自 XIB)中的 topLayoutGuide.lengthviewWillAppear 之后设置,我不知道如何挂钩 topLayoutGuide.length 的更改以最初设置 a 的 contentOffset表格视图。

UINavigationController 内模态显示UIViewController 的代码:

let viewController = UIViewController(nibName: "ViewController", bundle: nil)
let navigationController = UINavigationController(rootViewController: viewController)
present(navigationController, animated: true, completion: nil)

我关于topLayoutGuide.length的调试输出

Init view controller
-[UIViewController topLayoutGuide]: guide not available before the view controller's view is loaded
willMove toParentViewController  - top layout guide nan
Init navigation controller and pass view controller as root vc
Present navigation controller modally
viewDidLoad                      - top layout guide 0.0
viewWillAppear                   - top layout guide 0.0
viewWillLayoutSubviews           - top layout guide 64.0
viewDidLayoutSubviews            - top layout guide 64.0
viewWillLayoutSubviews           - top layout guide 64.0
viewDidLayoutSubviews            - top layout guide 64.0
viewDidAppear                    - top layout guide 64.0
didMove toParentViewController   - top layout guide 64.0
viewWillLayoutSubviews           - top layout guide 64.0
viewDidLayoutSubviews            - top layout guide 64.0

现在我在视图控制器中使用 bool 标志在 viewDidLayoutSubviews 中设置 contentoffset 一次,即使该方法被多次调用。

有什么更优雅的解决方案吗?

【问题讨论】:

  • 您是否尝试过在viewDidLoad 中设置布局锚点/布局约束。您可以粘贴代码显示您如何设置布局约束/锚点吗?
  • 在我看来,只要您使用自动布局,值并不重要

标签: ios swift uiviewcontroller autolayout


【解决方案1】:

documentation for the topLayoutGuide 明确声明:

viewDidLayoutSubviews() 方法的实现中查询此属性。

从你自己的检查来看,最早得到topLayoutGuide的实际长度的点是在viewWillLayoutSubviews()方法里面。但是,我不会依赖它,而是按照文档的建议在 viewDidLayoutSubviews() 中执行此操作。

不能早点访问属性的原因...

... 是布局指南是依赖于任何容器视图控制器布局的对象。当屏幕上需要视图时,视图会被懒惰地布置。因此,当您将 viewController 添加到 navigationViewController 作为其根视图控制器时,它尚未布局。

布局发生在您呈现navigationController 时。此时,两个视图控制器的视图都已加载(→ viewDidLoad()viewWillAppear()),然后触发布局传递。首先,布局navigationViewController的视图(布局流程:superview → subview)。导航栏的框架设置为 64 像素的高度。现在可以设置viewControllertopLayoutGuide。最后,viewController 的视图布局(→ viewWillLayoutSubviews()viewDidLayoutSubviews())。

结论:

根据布局指南的长度进行一些初始布局调整的唯一方法是您自己建议的方法:

  1. 在您的视图控制器中有一个布尔属性,您最初设置为 true

    var isInitialLayoutPass: Bool = true 
    
  2. viewDidLayoutSubviews() 内部检查该属性,并且仅在true 时执行您的初始布局:

    func viewDidLayoutSubviews() {
        if isInitialLayoutPass {
            tableView.contentOffset = CGPoint(x: 0, y: topLayoutGuide.length)
        }
    }
    
  3. viewDidAppear()内部,设置属性为false,表示初始布局完成:

    override func viewDidAppear() {
        super.viewDidAppear()
        isInitialLayoutPass = false
    }
    

我知道它仍然感觉有点老套,但恐怕这是唯一的方法(我能想到),除非你想使用 key-value-observing (KVO)在我看来并没有让它更整洁。

【讨论】:

  • 哇。非常感谢您的详细解释!
  • 这真的很棒,也感谢您的回答和问题!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多