在 AppKit 中,layout() 是 NSView 的一个生命周期方法,但它的调用需要一些前提和特点。
layout() 默认情况下只会在使用自动布局(Auto Layout)时才会触发。如果没有使用约束系统(NSLayoutConstraint 等),通常不会自动调用。
layout() 方法的作用
layout() 方法用于:
更新 view 中子视图的位置或尺寸,或者重新设置自身的子 layer、布局结构等。
它是 AppKit 自动布局(Auto Layout)机制中的一部分,类似于 UIKit 的 layoutSubviews()。
调用时机
1、使用 Auto Layout 的时候:
如果使用约束(NSLayoutConstraint)来布局视图,系统会在布局阶段自动调用 layout()。
2、显式标记视图需要布局:
可以调用:
view.needsLayout = true
然后系统会在合适的时机自动调用 layout()。
3、视图的尺寸或位置变化时(在部分情况下)
特别是使用了约束系统或者视图层级中有 translatesAutoresizingMaskIntoConstraints = false。
不调用layout的时机
如果没有使用自动布局(Auto Layout),而是纯手动设置 frame,那默认不会自动调用 layout()。这也是 “只有自动布局时才会调用”的原因。
强制调用的方式
如果希望手动调用 layout()(例你不是用 Auto Layout,但仍然希望有布局逻辑):
view.layout() // 手动触发 layout
或者
view.needsLayout = true
view.layoutSubtreeIfNeeded() // 延迟触发(和 UIKit 的 setNeedsLayout + layoutIfNeeded 类似)
使用示例
class CustomView: NSView {
override func layout() {
super.layout()
print("layout 被调用")
// 自定义布局逻辑
for subview in subviews {
subview.frame = bounds.insetBy(dx: 10, dy: 10)
}
}
}
总结
使用Auto Layout、设置needsLayout、调用layout()和调用layoutSubtreeIfNeeded()时,都会调用layout()。
如果使用frame手动布局,则不会调用layout()。
layout()属于视图布局阶段的一部分,例如bounds在初始化时为(0,0,0,0),而在layout()中就有数值,这时因为layout()是在视图的尺寸被确定后调用的。
在NSView中设置与尺寸有关的图形、布局时,推荐调用layout()方法。
相关文章
1、macOS视图NSView:https://fangjunyu.com/2025/07/01/macos%e8%a7%86%e5%9b%bensview/
2、NSView初始化时bounds属性失效的问题:https://fangjunyu.com/2025/08/02/nsview%e5%88%9d%e5%a7%8b%e5%8c%96%e6%97%b6bounds%e5%b1%9e%e6%80%a7%e5%a4%b1%e6%95%88%e7%9a%84%e9%97%ae%e9%a2%98/