59

我正在使用 iOS 6 自动布局进行开发

我想记录一条显示视图框架宽度的消息。

我可以在屏幕上看到 textView。

但是我得到宽度和高度为零,我错过了什么吗?

NSLog(@"textView    = %p", self.textView);
NSLog(@"height      = %f", self.textView.frame.size.height);
NSLog(@"width       = %f", self.textView.frame.size.width);

textView    = 0x882de00
height      = 0.000000
width       = 0.000000
4

9 回答 9

155

其实,上面的答案并不完全正确。我跟着他们,一次又一次地得到零。

诀窍是将与帧相关的代码放置在viewDidLayoutSubviews方法中,该方法

通知视图控制器它的视图刚刚布置了它的子视图。

不要忘记这个方法被多次调用,并且不是 ViewController 生命周期的一部分,所以在使用它时要小心。

希望它对某人有所帮助。

只是想补充一点,对于我的没有横向模式的程序不使用自动布局要简单得多......我试过了,虽然=D

于 2013-01-03T21:11:14.557 回答
59

我认为在您调用此功能时,自动布局还没有时间来布局您的视图。自动布局在调用时还没有发生viewDidLoad,因为它是在视图加载后调用的,并且只有在视图被放置到视图控制器的视图层次结构中并最终布局(在视图的layoutSubviews方法中)之后。

编辑:这个答案指出了为什么问题中的场景不起作用。@dreamzor 的回答指出了将代码放置在何处以解决问题。

于 2012-09-21T08:52:19.597 回答
33

包括在你的 viewDidLoad()

self.view.setNeedsLayout()
self.view.layoutIfNeeded()

在访问 yourview.frame.size.width 之前

于 2015-03-04T15:29:24.550 回答
31

解决方案

  • 将该代码放入viewDidAppear

原因

  • viewDidLoad在自动布局完成之前发生。因此,在 xib 中指定的自动布局尚未设置位置
  • viewDidAppear自动布局完成后发生。
于 2012-09-28T02:38:52.780 回答
13

实际上,我设法在我的代码之前强制更新布局viewDidLoad

override func viewDidLoad() {
        super.viewDidLoad()

        println("bounds before \(self.previewContainer.bounds)");
        //on iPhone 6 plus -> prints bounds before (0.0,0.0,320.0,320.0)

        self.view.setNeedsLayout()
        self.view.layoutIfNeeded()

        println("bounds after \(self.previewContainer.bounds)");
        //on iPhone 6 plus -> prints bounds after (0.0,0.0,414.0,414.0)

        //Size dependent code works here
        self.create()
    }

更新:这似乎不再起作用

于 2014-12-18T13:51:37.050 回答
10

这真是一个奇怪的功能。但我发现:

如果您想在不使用 layoutsubviews 方法的情况下获取框架,请使用此方法:

dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"View frame: %@", NSStringFromCGRect(view.frame));
    });

这真的很奇怪!!!

于 2015-12-29T13:02:02.380 回答
7

上述答案都没有对我完全有效,除了viewDidLoad它的副作用是直到视图动画后才显示我想要的内容,这看起来很糟糕。

viewDidLayoutSubviews 应该是运行依赖于完整自动布局的代码的正确位置,但正如其他人指出的那样,它在最近的 iOS 版本中被多次调用,你不知道哪个是最终调用。

所以我用一个小技巧解决了这个问题。在我的故事板中,mySubview应该小于其包含的self.view. 但是viewDidLayoutSubviews第一次调用时,mySubview宽度仍然为 600,而self.view似乎设置正确(这是一个 iPhone 项目)。所以我所要做的就是监控后续调用并检查相对宽度。一旦mySubview小于self.view我可以确定它已正确布局。

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    if self.mySubview.bounds.size.width < self.view.bounds.size.width {

        // mySubview's width became less than the view's width, so it is
        // safe to assume it is now laid out correctly...

    }
}

这具有不依赖硬编码数字的优势,因此它可以在所有 iPhone 外形尺寸上工作,例如。当然,它可能不是所有情况下或所有设备上的灵丹妙药,但可能有许多巧妙的方法可以对相对大小进行类似的检查。

不,我们不应该这样做,但是在 Apple 给我们一些更可靠的回调之前,我们都会坚持下去。

于 2015-11-04T20:44:46.347 回答
3

您只能在第一次布局通过后找出大小。或者,在您获得视图的实际宽度后,只需调用以下方法。

[yourView layoutIfNeeded];
于 2017-07-08T10:39:32.770 回答
0

我同意“user1046037”的解决方案

如果您同时使用 atuoLayout 指南和代码,则最好将框架(或 NSlayoutConstraints)编程放入“ ViewDidAppear ”中,尤其是在为多个设备设计 UI 时。

根据我的测试,iOS14 将在“ ViewDidLoad ”之前从屏幕(默认 iPhone 11 Pro Max)获取自动布局,并在“ ViewDidAppear 中更新它。

对于不熟悉视图循环的人,它的“从情节提要加载视图”->“ ViewDidLoad ”->“ ViewWillAppear ”->“ ViewDidAppear ”。

于 2020-11-09T17:52:10.030 回答