I have following view controller:
class ViewController: UIViewController {
lazy var superView: UIView = {
let view = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
view.backgroundColor = UIColor.white
return view
}()
lazy var childView: UIView = {
let view = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
view.backgroundColor = UIColor.black
return view
}()
var boundObservation: NSKeyValueObservation?
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.orange
self.view.addSubview(self.superView)
self.superView.center = CGPoint(
x: self.view.frame.width / 2.0,
y: self.view.frame.height / 2.0
)
self.superView.addSubview(self.childView)
self.childView.center = CGPoint(
x: self.superView.frame.width / 2.0,
y: self.superView.frame.height / 2.0
)
self.childView.autoresizingMask = .flexibleWidth
let button = UIButton(type: .system)
button.setTitle("Tap me!", for: .normal)
button.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)
self.view.addSubview(button)
button.translatesAutoresizingMaskIntoConstraints = false
button.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
button.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor, constant: -24).isActive = true
self.boundObservation = self.childView.observe(
\UIView.bounds,
options: .new,
changeHandler: { view, change in
print(change.newValue ?? "nil")
})
}
@objc func buttonTapped(_ sender: UIButton) {
let view = self.superView
let previousSize = view.bounds.size
view.bounds.size = CGSize(width: previousSize.width + 50, height: previousSize.height + 20)
}
}
My childView
get's automatically resized due to autoresizing mask when superView
is resized. But KVO observation is not getting called. Why is KVO not working in this case?
My issue was solved by observing \.layer.bounds
instead of \UIView.bounds
because I learned that the layer is the “source of truth” for a view’s layout, so I suspected the autoresizing mask was directly modifying the layer bounds without going through UIView.bounds