Reputation: 312
I have a uiview
in the center of the viewcontroller
. There is a uilabel
above (A) and below (B) this uiview
.
I want to programmatically change the bottom constraint of this uiview
so that the distance above and below the uiview
are equal to each other as screen size changes. So calculating the distance between top uiview
to bottom of uilabel
(A) and distance between bottom uiview
to top of uilabel
(B), dividing by 2 and then setting the bottom constraint constant accordingly.
I have the calculation done, but it only seems to work when i place it in viewDidAppear
and i need the constraints and views to be in their right place before the user is able to see the objects. Is this possible to do in viewWillAppear
. it feels like all the elements are not set until viewDidAppear
for me to calculate correctly..i believe it has to do with the lifecycle of autolayout
not completing prior to the calculation..
let topDistance = view.frame.minY - ALabel.frame.maxY
let bottomDistance = BLabel.frame.minY - view.frame.maxY
let total = topDistance + bottomDistance
bottomConstraint.constant = total / 2
Below is a before/after example of the desired result where the purple uiview
has a bottom constraint to the bottom orange uilabel
. when the screen size increases in length, as an example, i want the bottom constraint to have the same constant as the distance between the purple uiview
and top orange uilabel
. The top uilabel
has a top constraint to the top and the bottom uilabel
has a bottom constraint to the bottom.
Upvotes: 0
Views: 1312
Reputation: 77578
To try and answer your question:
You're right, that auto-layout has not finished doing its work in viewDidLoad()
or even viewWillAppear()
. Generally, when you need to do layout adjustments like that, you want to do it in viewDidLayoutSubviews()
. From Apple's docs:
viewDidLayoutSubviews
When the bounds change for a view controller's view, the view adjusts the positions of its subviews and then the system calls this method.
However, if I understand what you're actually trying to do...
By using a UIStackView
you can avoid needing to use any code.
Embed your labels, views, buttons, etc in a Vertical UIStackView
. Set the properties to:
Alignment: Fill (or Leading or Center as suits your layout)
Distribution: Equal Spacing
Spacing: 0
Constrain the stack view's Top to the Top of the view (plus any desired padding) and the Bottom to the Bottom of the view (plus any desired padding).
Result with iPhone SE size:
Result with iPhone 8 size:
Result with iPhone XS size:
And, here's iPhone 8 with a couple additional elements of varying heights:
As you see, the elements have equal vertical spacing between them, and it's all handled by the stack view.
Upvotes: 1
Reputation: 638
You can use Dispatch Queue for this:
DispatchQueue.main.async {
let topDistance = view.frame.minY - ALabel.frame.maxY
let bottomDistance = BLabel.frame.minY - view.frame.maxY
let total = topDistance + bottomDistance
bottomConstraint.constant = total / 2
self.view.layoutIfNeeded()
}
Upvotes: 1
Reputation: 566
When I want to set constraints programmatically I usually proceed like this :
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(v)
v.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 20).isActive = true
v.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -20).isActive = true
v.heightAnchor.constraint(equalToConstant: 100).isActive = true
v.centerYAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerYAnchor).isActive = true
Upvotes: 1
Reputation: 338
When you use View did appear is already when user see the VeiwController, Use viewDidLoad instead , u can't use viewWillAppear , because View isn't loaded yet.
Use it on:
override func viewDidLoad() {
super.viewDidLoad()
}
And u can try call
self.view.layoutIfNeeded()
Upvotes: 1
Reputation: 4570
Write layoutIfNeeded
after update constraint.
let topDistance = view.frame.minY - ALabel.frame.maxY
let bottomDistance = BLabel.frame.minY - view.frame.maxY
let total = topDistance + bottomDistance
bottomConstraint.constant = total / 2
self.view.layoutIfNeeded()
Upvotes: 1