Swift 4:如何在通过代码添加约束后获取UIView的bounds
解决Auto Layout约束生效后无法获取正确bounds的问题
哈哈,这个坑我刚踩过不久!问题出在Auto Layout的异步布局机制上——你给previewView加完约束后,系统并不会立刻计算并更新它的bounds,而是要等到下一个布局周期才会完成这件事。所以你紧接着去访问bounds,拿到的肯定是创建时的初始值(比如CGRectZero),而不是约束生效后的实际尺寸。
下面给你三个靠谱的解决方案,按推荐优先级排序:
1. 在viewDidLayoutSubviews中获取(最推荐)
这个方法是系统在视图布局完成后自动调用的,每次视图尺寸变化(比如屏幕旋转、父视图尺寸改变)都会触发,在这里能稳定拿到约束生效后的最终bounds:
Swift示例:
override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() // 这里的previewView.bounds就是约束生效后的实际尺寸 let actualBounds = previewView.bounds print("PreviewView实际bounds: \(actualBounds)") // 在这里执行需要用到bounds的逻辑 setupPreviewContent(with: actualBounds) }
Objective-C示例:
- (void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; CGRect actualBounds = self.previewView.bounds; NSLog(@"PreviewView实际bounds: %@", NSStringFromCGRect(actualBounds)); [self setupPreviewContentWithBounds:actualBounds]; }
2. 手动触发布局后立即获取
如果必须在当前代码上下文(比如某个按钮点击事件、初始化方法里)拿到bounds,可以强制系统立即完成布局计算,再访问bounds:
Swift示例:
// 先给previewView设置好所有约束 previewView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ previewView.topAnchor.constraint(equalTo: view.topAnchor, constant: 20), previewView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), previewView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), previewView.heightAnchor.constraint(equalToConstant: 300) ]) // 强制系统立即完成布局更新 previewView.layoutIfNeeded() // 现在就能拿到正确的bounds了 let updatedBounds = previewView.bounds print("更新后的bounds: \(updatedBounds)")
注意点:
- 调用
layoutIfNeeded()前,必须确保所有约束都已经设置完成,否则依然会拿到错误的尺寸。 - 这个方法适合在非布局周期的代码里临时获取尺寸,不建议频繁调用,因为会触发同步布局计算,可能影响性能。
3. 避免的错误做法
不要用DispatchQueue.main.asyncAfter(deadline: .now() + 0.1)这种延迟执行的方式,因为不同设备的布局速度不一样,0.1秒在老设备上可能还没完成布局,导致依然拿不到正确值,稳定性极差。
内容的提问来源于stack exchange,提问作者Yagiz Ozen
相关产品推荐
相关产品推荐

