Autolayout - When using NSLayoutAttributeCenterX what scale does the multiplier use?
When using the attribute, a NSLayoutAttributeCenterX
multiplier of 1 results in a center that matches the specified view. Increasing the value moves it to the left and decreases to 0, moves it to the right.
I was able to achieve roughly the results I want through trial and error (3 views evenly spaced across the super view) using multipliers of 2.5, 1 and 0.625. During the confusion, I found that 200 is centered on the left edge of the said view (also zooms in more than it does not move the view), and 0.5 is centered on the right edge (decreasing towards 0 moves the view further to the left).
So here are my questions:
- what is it?
- is there a formula I can use to accurately position the views this way, or will it be trial and error forever?
- Why do they do it?
source to share
Figuring out what the center constraint means when the multiplier is not 1.0 is tricky. I have been experimenting in Xcode 6 and here are my findings.
The corresponding constraint has the form A.center.x = B.center.x * m + c
, where A
and B
are the considered types, m
is the constraint multiplier, and c
is the constraint constant.
Suppose B center.x
is fixed by some other constraint. Then I believe that autorun behaves as if it were using this algorithm:
-
Find the closest common ancestor of A and B. Name this common ancestor G.
-
Let bxg = Bx center in coordinate system G. You can compute this in code as
CGFloat bxg = [G convertPoint:B.center fromView:B.superview].x
. -
Calculate axg = Desired x-center in G-coordinate system.
CGFloat axg = bxg * m + c
... -
Convert axg to coordinate system
A.superview
and save it asA.center.x
.
Okay, so with all that in mind, how do we use center constraints to achieve your "evenly distributed views" goal? We don't.
Here's the problem. Suppose all three of your subs have the same width, w. (The problem is even more complicated if they have different widths.) And let's say the container view has width W. There are four margins (one to the left of the leftmost subview, one between the left subview and the middle subview, one between the middle subhead and the right subview. and one to the right of the right peep.)
So the field width should be (W - 3 w) / 4. Then we want to connect this to another constraint somehow. You wanted to use the center constraint, but for the sake of simplicity, consider constraining the left edge in the left view L. We want the constraint to be L.left = (W - 3 w) / 4. This limitation is too difficult for autolayout to handle directly. Autodetect constraints can only include two view attributes, but this is related to three.
The solution is to introduce spacer views. Let's start with our three desired areas:
I've already constrained each of these three subzones to 80x80 and vertically centered.
Now I will add four spacer views, shown in gray:
I have limited each spacer height and vertical center, but I do not have a limit on their width. Next, I will constrain all spacers to the same width:
Then I will bind each leading and trailing edge of the spacer to its nearest neighbors by manually setting the constants to zero. This is how I make my first spacer:
I do the same for the other three pads. I will not show it here.
When I select a view controller and ask Xcode to update all frames, I get evenly spaced views:
Since I don't really want the spacers to be visible at runtime, I'll select them and close them. The hidden views are still part of the layout.
Now what if the subviews don't have the same width? Let's change the width of the blue subset:
Automatic layout updates the frames so that the spacers continue to have the same width.
source to share
I figured out that if you place a view aligned to the center of the supervisor X (and I believe this will be true for the Y-axis as well), you can calculate the multiplier factor from the expected center of view using this:
Coeff = superview.width / view.center.X * 0.5
I. You have a supervisor with width = 600, you need to place the view centered at 0.25 of the supervisor width, then the center of view = 150
Coeff = 600 / 150 * 0.5 = 2
If you want a symmetrical look then
Coeff = 600 / 450 *0.5 = 0.666
Therefore, if you know that the center of vision (CoV) is 0.25, then the formula would be:
Coeff = 1 / CoV * 0.5
source to share