提问人:Deepak Sharma 提问时间:7/2/2023 最后编辑:Deepak Sharma 更新时间:7/3/2023 访问量:52
AutoLayout layoutIfNeeded 边界更新时间
AutoLayout layoutIfNeeded bounds update time
问:
我的自定义 UIView 中有以下代码。这从或初始值设定项调用:init(frame:)
init(coder:)
private func setupContentView() {
contentView = ContentView(frame: .zero)
contentView.translatesAutoresizingMaskIntoConstraints = false
addSubview(contentView)
contentView.leftAnchor.constraint(equalTo: leftAnchor, constant:thumbWidth).isActive = true
contentView.rightAnchor.constraint(equalTo: rightAnchor, constant: -thumbWidth).isActive = true
contentView.topAnchor.constraint(equalTo: topAnchor).isActive = true
contentView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
contentView.clipsToBounds = true
contentView.isUserInteractionEnabled = true
contentView.layoutIfNeeded()
NSLog("ContentView bounds \(contentView.bounds), view bounds \(self.bounds)")
}
我知道调用时,它会在完成后立即更新帧。但我并不总是看到这种行为。下面的转储显示 的边界仍然是 0 宽度和 0 高度。我错过了什么?layoutIfNeeded
contentView
NSLog
contentView
ContentView bounds (0.0, 0.0, 0.0, 0.0), view bounds (0.0, 0.0, 774.0, 84.0)
答:
如果您想知道布局后内容视图的边界是什么,那么需要布局的不是内容视图,而是它的监督视图。改变
contentView.layoutIfNeeded()
自
contentView.superview?.layoutIfNeeded()
甚至更可靠,比如说
contentView.superview?.layoutIfNeeded()
CATransaction.setCompletionBlock {
NSLog("ContentView bounds \(contentView.bounds), view bounds \(self.bounds)")
}
这可确保在登录之前布局已完成。
评论
self.bounds
ContentView bounds (0.0, 0.0, 0.0, 0.0), view bounds (0.0, 0.0, 28.0, 0.0)
contentView.superview?.layoutIfNeeded()
您的自定义子类不会“单独存在”。UIView
让我们从一个简单的“内容视图”子类开始:
class ContentView: UIView {
}
我们将定义一个自定义视图,如下所示:
class YourCustomView: UIView {
var contentView: ContentView!
let thumbWidth: CGFloat = 40.0
override init(frame: CGRect) {
super.init(frame: frame)
print(#function)
setupContentView()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
print(#function)
setupContentView()
}
private func setupContentView() {
contentView = ContentView(frame: .zero)
contentView.translatesAutoresizingMaskIntoConstraints = false
addSubview(contentView)
contentView.leftAnchor.constraint(equalTo: leftAnchor, constant:thumbWidth).isActive = true
contentView.rightAnchor.constraint(equalTo: rightAnchor, constant: -thumbWidth).isActive = true
contentView.topAnchor.constraint(equalTo: topAnchor).isActive = true
contentView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
contentView.clipsToBounds = true
contentView.isUserInteractionEnabled = true
contentView.layoutIfNeeded()
NSLog("A: ContentView bounds \(contentView.bounds), view bounds \(self.bounds)")
self.layoutIfNeeded()
NSLog("B: ContentView bounds \(contentView.bounds), view bounds \(self.bounds)")
self.superview?.layoutIfNeeded()
NSLog("C: ContentView bounds \(contentView.bounds), view bounds \(self.bounds)")
CATransaction.setCompletionBlock {
NSLog("D: ContentView bounds \(self.contentView.bounds), view bounds \(self.bounds)")
}
}
}
现在,在 Storyboard 中,我们将添加一个 ,将其类赋给 ,并为其提供 top/leading/bottom/constraints of :UIView
YourCustomView
80
运行时,我们得到以下输出:
init(coder:)
A: ContentView bounds (0.0, 0.0, 0.0, 0.0), view bounds (0.0, 0.0, 233.0, 599.0)
B: ContentView bounds (0.0, 0.0, 0.0, 0.0), view bounds (0.0, 0.0, 80.0, 0.0)
C: ContentView bounds (0.0, 0.0, 0.0, 0.0), view bounds (0.0, 0.0, 80.0, 0.0)
D: ContentView bounds (0.0, 0.0, 153.0, 599.0), view bounds (0.0, 0.0, 233.0, 599.0)
接下来,我们将给它明确的宽度/高度约束,而不是尾随/底部约束:
现在,当我们运行它时,我们得到这个:
init(coder:)
A: ContentView bounds (0.0, 0.0, 120.0, 500.0), view bounds (0.0, 0.0, 200.0, 500.0)
B: ContentView bounds (0.0, 0.0, 120.0, 500.0), view bounds (0.0, 0.0, 200.0, 500.0)
C: ContentView bounds (0.0, 0.0, 120.0, 500.0), view bounds (0.0, 0.0, 200.0, 500.0)
D: ContentView bounds (0.0, 0.0, 120.0, 500.0), view bounds (0.0, 0.0, 200.0, 500.0)
正如我们所看到的,在第一种情况下 - 我们设置尾部/底部 - 在自动布局期间还不知道最终的宽度和高度是多少。init(coder)
YourCustomView
在第二种情况下 - 我们设置宽度/高度 - 在自动布局期间已经知道最终的宽度和高度是多少。init(coder)
请注意,如果我回到 Storyboard 并使用以下方法进行布局:iPhone SE (1st Generation
并在 上运行应用程序,我们得到以下输出:iPhone 14 Pro
init(coder:)
A: ContentView bounds (0.0, 0.0, 0.0, 0.0), view bounds (0.0, 0.0, 160.0, 388.0)
B: ContentView bounds (0.0, 0.0, 0.0, 0.0), view bounds (0.0, 0.0, 80.0, 0.0)
C: ContentView bounds (0.0, 0.0, 0.0, 0.0), view bounds (0.0, 0.0, 80.0, 0.0)
D: ContentView bounds (0.0, 0.0, 153.0, 599.0), view bounds (0.0, 0.0, 233.0, 599.0)
请注意,这次自定义视图边界从以下位置开始:
(0.0, 0.0, 160.0, 388.0)
它是从我的故事板布局中拾取的。
文档说:.layoutIfNeeded()
使用此方法可强制视图立即更新其布局。使用“自动布局”时,布局引擎会根据需要更新视图的位置,以满足约束的变化。
您遇到的混淆是视图层次结构的其余部分可能未初始化...并且可能(可能会)改变在您拨打该电话之后。
评论
init(coder:)
setupContentView()