从 xib 加载视图控制器返回错误的帧
Posted
技术标签:
【中文标题】从 xib 加载视图控制器返回错误的帧【英文标题】:Loading View Controller from xib return wrong frame 【发布时间】:2020-12-18 06:54:13 【问题描述】:我在从 xib 加载视图控制器时遇到问题
我有一个 xib 文件,其中包含一个视图控制器和一个子视图,如下图所示。请注意,我在 xib 中使用 iPhone 11 Pro Max
(屏幕宽度 = 414)
子视图有 8 个到其父视图的前导和尾随。
问题是当我在 iPhone 12 Pro Max(屏幕宽度 = 428)上运行应用程序时,我检查屏幕尺寸和子视图尺寸的值,它返回奇怪的值。这是我的代码:
public override func viewDidLoad()
super.viewDidLoad()
print(view.frame) // (0.0, 0.0, 414.0, 896.0)
print(collageView.frame) // (8.0, 210.0, 398.0, 398.0)
public override func viewDidLayoutSubviews()
super.viewDidLayoutSubviews()
print(view.frame) // (0.0, 0.0, 428.0, 926.0) updated
print(collageView.frame) // (8.0, 210.0, 398.0, 398.0) ??
let width = collageView.frame.width
let height = collageView.frame.height
let frames = self.frames?(CGSize(width: width, height: height)) ?? []
for i in 0..<frames.count
let componentView = CropComponentView(frame: frames[i])
componentView.image = images[i]
collageView.addSubview(componentView)
我的问题是:
我们如何在 viewDidLoad 中获得正确的屏幕尺寸?为什么子视图的框架不像屏幕大小那样更新?
【问题讨论】:
您无法在viewDidLoad
中获取任何尺寸信息。太早了。 programmingios.net/premature-layout
@matt 我接受这一点,但是关于子视图框架的问题如何。子视图如何有正确的框架?
@TungVuDuc 试试layoutIfNeeded()
,然后在 viewdidload 中检查框架。让我知道它是否有效
@dahiya_boy call layoutIfNeeded() inside viewDidLayoutSubviews bellow super.viewDidLayoutSubviews() 然后collageView的框架被更新
另外,这并不重要,但您应该删除 Center X 约束,因为它不是必需的。如果视图具有彼此相等的前导和尾随约束,则根据定义将其水平居中。
【参考方案1】:
我们如何在 viewDidLoad 中获得正确的屏幕尺寸?
排序答案是您无法在 viewDidLoad() 中获得最终视图(viewController 的)大小,因为该视图刚刚从 xib 加载并且具有在 xib 中设置的占位符框架。需要将其添加到视图层次结构中(例如添加到父视图/窗口),然后才能应用布局规则。视图将在视图加载后立即添加。
控制器可用的宽度/高度由容器控制器(如果有)以及设备方向和状态栏状态决定。例如,如果您的控制器被添加到 tabbarcontroller 中,那么如果 tabbar 正在显示,它将具有更少的垂直空间。如果显示状态栏并且您有来电,则状态栏的大小将发生变化,留下更少的垂直空间。如果你在 SplitViewController 容器中显示你的控制器,那么它的宽度会更小。
如果您假设它将占用整个屏幕尺寸,您可以在 viewDidLoad() 中计算帧:
override func viewDidLoad()
//...
var screenSize = UIScreen.main.bounds
var collageViewFrame: CGSize = self.collageView.frame.sizeThatFits(screenSize)
为什么子视图的框架没有像屏幕大小那样更新?
从documentation 到-viewDidLayoutSubviews
:
但是,调用此方法并不表示 视图的子视图的个别布局已调整。
如果您需要正确的框架,您需要在该子视图中调用layoutIfNeeded
方法。
还请this回答。
【讨论】:
Interface Builder 上显然没有丢失/错误约束的迹象,因此 1:1 的比例可能在其自身,因此所有约束都得到满足。 @Kalzem 你是对的。看来 viewDidLayoutSubviews 并不表示视图的子视图的个别布局已经调整。在答案***.com/questions/28601742/… 中查看更多信息。我会更新并更正我的答案 所以在阅读您的参考后,我们是否应该将所有自动布局设置移动到 viewDidAppear 以保证所有帧都正确? @ChristosKoninis 是的,要么将其移动到 viewDidAppear,要么如果您知道超级视图的大小,您可以调用方法 sizeThatFits(SizeOfSuperView) 来获取框架,在大多数情况下,超级视图的大小是 UIScreen.main。界限以上是关于从 xib 加载视图控制器返回错误的帧的主要内容,如果未能解决你的问题,请参考以下文章