Given this example:
When I add a view programatically and set its frame...
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let subview = UIView()
subview.backgroundColor = .red
subview.frame = view.frame
view.addSubview(subview)
}
}
It doesn't get resized when I rotate the screen
However, when I add a view that is generated by a view controller like so:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let subview = UIViewController().view!
subview.backgroundColor = .red
subview.frame = view.frame
view.addSubview(subview)
}
}
It gets resized when I rotate the screen.
What is happening? Why those two views handle trait collection changes differently?
Does it implies that I should use constraints no matter what (even in custom presentation modal transitions and push navigation transitions, on which Apple's doc seems to recommend to use frames?)
This is very odd...
let subviewFromVC = UIViewController().view!
You are creating a new instance of a UIViewController()
(NOT related to the current view controller), and grabbing a reference to its .view
.
Then you add that view as a subview, and set its frame.
The "base" view of a UIViewController
comes with:
.autoresizingMask = [.flexibleWidth, .flexibleHeight]
so it "auto-resizes" ...
However, when you do this:
let subview = UIView()
subview.backgroundColor = .red
subview.frame = view.frame
view.addSubview(subview)
By default, subview
is created with:
.autoresizingMask = []
so it doesn't "auto-resize" ...
If you want subview
to auto-resize based on the frame you set, you need to set that mask:
let subview = UIView()
subview.backgroundColor = .red
subview.frame = view.frame
subview.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(subview)
If you are creating a new subview - or, probably, multiple subviews - that auto-resize and automatically adjust their positions, you will need a combination of the various .autoresizingMask
flags:
.flexibleWidth, .flexibleHeight,
.flexibleTopMargin, .flexibleBottomMargin,
.flexibleLeftMargin, .flexibleRightMargin,
Without seeing the UI layout you're going for, can't offer much else -- but that should at least get you on your way.
Edit - mixing frame
and constraints...
The reason we see something like viewToPresent.frame.origin.x =
in a custom UIPresentationController
is because that view is instantiated with .autoresizingMask = [.flexibleWidth, .flexibleHeight]
. So, to "slide it in from the left" for example, we'd animate it along these lines:
viewToPresent.frame.origin.x = -viewToPresent.frame.width
UIView.animate(withDuration: 0.3, animations: {
viewToPresent.frame.origin.x = 0.0
})
That can also be done with constraints, but for this use-case setting frame values is (perhaps) easier.
For the "dimming view," though, it would seem to make more sense to use constraints, since its size/position won't be animated.
What often is not obvious is that:
someView.translatesAutoresizingMaskIntoConstraints = true
does Not mean auto-layout is not being used... it means that the view's .autoresizingMask
is being translated into constraints.