Autolayout center y alignment strange behaviour when setting multiplier - ios

I have a helper view with dynamic height in my storyboard, this is a common practice to make layout responsive.
However, something strange happens when I introduce multipliers.
The blue button is aligned center y to the white view on the left:
Changing multiplier value into 0.5 should align the button to center of first half of the white view, at least it works this way when aligning to superview.
Instead I end up with sth like this:
The blue button height is equal to 0.05 times th height of the superview. The white view height is equal to 4 timees the height of the blue button
I have no idea what is the problem here that causes this weird alignment. I suspected it might be something with dynamic height value, so I tried setting explicit height value but the result was exactly the same.

You said that if button is Center Y with multiplier 0.5, than it should be positioned at the 1/4 of that white view.. No thats not worked like that .. lets check it with equation
multiplier works with this equation
FirstItem.Attribute1 = (SecondItem.Attribute2 * Multiplier) + Constant
Your constraint is Button.Center Y = BlankView.center Y .. so this is how equation filled up
Button.Center Y = (BlankView.center Y * 1) + 0
So the question is what is the value of BlankView.Center Y ...
answer is
BlankView.Center Y = HeightOfSuperviewOFBlankView - (Y positionOFBlankView + (BlankViewHeight / 2))
// in your case it would be 603 - (483 +(120/ 2)) = 543
Now move to Your equation Center Y with multiplier 0.5
Button.Center Y = (543 * 0.5) + 0 // 271.5
because of that your button position with Center Y is placed at
Button.Center Y = 271.5 - (buttonHeight / 2)
// if we take buttonHeight = 30 than it should be 257.5 (approx 257)
I hope now you understand how center Y with multiplier works...

Related

Is there way to determine height of rectangle in centimetres, provided I know left, right, top, bottom co-ordinates?

I'm using opencv, I have left, right, top, bottom co-ordinates of a rectangle.
I want to measure width and height of the rectangle in centimeters. How do I do that?
I tried to find euclidean distance like this:
D = dist.euclidean((top, left), (top, right)), but am not sure whether it is right or not, because I want a value of height and width in centimeters
Code segment that I use to determine the co-ordinates
(xmin, ymin, xmax, ymax) = (box[num][1], box[num][0], box[num][3], box[num][2])
(left, right, top, bottom) = (xmin * im_width, xmax * im_width, ymin * im_height, ymax * im_height)

Is it ok to actually use multipliers on anchors?

Is it ok to use multipliers on anchors and on centers ?
For me, at least for start this made no sense at all, but then I dig in a bit and I saw that this actually works.
So let me get this strait.
Tell me if I'm wrong please.
1) Leading with multiplier of 1 = Trailing ? I've seen that leading with multiplier of 0.1, means 10% inside (based on width).
2) Center with multiplier of 2 = Trailing ? By the assumption that center means trailing / 2 or leading * 0.5 ?
As far as I learned, the multiplier actually multiplies by the width / height based on the axis.
This means that the following constraints are equivalent ?
C1.axis = C2.axis * M + C <=> C1.axis = C2.axis + axisLength * M + C ?
So the multiplier just adds that multiple of the width or height ?
UPDATE:
So to clear things out with info from the accepted answer.
CenterX_or_Y = Width_or_Height / 2
Trailing - Leading = Width (in therms of size)
Bottom - Top = Height (in therms of size)
When you actually use multipliers on Leading/Trailing/Top/Bottom you are actually using the multipliers on the above sizes (width or height).
Using Multipliers on sizes is pretty straight-forward... I want my subview to be 80% of of the width of its superview, so I just set Equal widths with a Multiplier of 0.8
However, it can get confusing when using Multipliers on Leading / Trailing / Center / etc.
From Apple's Auto Layout Guide:
So, for example, let's say:
Red Leading is set to Blue Trailing, Constant 8, Multiplier 1
Blue Leading is at 0, and width is 100
Red's Leading will be (1.0 x 100) + 8 = 108
To be clear, though, Blue's Trailing is not the same as its Width.
Suppose Blue's Leading is at 50? If its Width is 100, its Trailing will be 150, so:
Red's Leading will be (1.0 x 150) + 8 = 158
Now, put Blue's Leading back to 0 but let's change the Multiplier to 0.75
Red's Leading will be (0.75 x 100) + 8 = 83
and, if Blue's Leading is 50, then Blue's Trailing is 150:
Red's Leading will be (0.75 x 150) + 8 = 120.5
Just refer back to the formula to keep things straight:
item1.attribute = multiplier * item2.attribute + constant
Here's a visual example to clarify. All labels are 100x40, and each Green label is constrained Green.Leading = Blue.Trailing + Constant: 8
For Set #1, the Multiplier is 1.0 - for sets #2, #3 and #4, the Multiplier is 0.5.
Set 1, Blue's Leading is 0, and Green's Multiplier is 1 ... This is what one normally sees, and it is obvious - Green is 8-pts from Blue's Trailing, which is (Blue.Leading + Blue.Width), or
1.0 * (0 + 100) = 100
100 + 8 = 108
Set 2, Blue's Leading is still 0, but Green's Multiplier is 0.5 ... so Green is 8-pts from Blue's Trailing, which is (Blue.Leading + Blue.Width), * 0.5, or
0.5 * (0 + 100) = 50
50 + 8 = 58
Set 3, Blue's Leading is now 80, Green's Multiplier is still 0.5 ... so Green is 8-pts from Blue's Trailing, which is (Blue.Leading + Blue.Width), * 0.5, or
0.5 * (80 + 100) = 90
90 + 8 = 98
Set 4 looks odd. Blue's Leading is now 200, Green's Multiplier is still 0.5 ... so Green is 8-pts from Blue's Trailing, which is (Blue.Leading + Blue.Width), * 0.5, or
0.5 * (200 + 100) = 150
150 + 8 = 158
As we see, in Set #4 Green ends up being Left of Blue, which is correct, but not all that intuitive.

iOS constraint equation values

I'm trying to find out what the values of the left and right views in a constraint equation are.
Currently this is how I see it.
The origin-point (0,0) in the coordinate system is at the top left.
Therefore views.attribute that are closer to the top and left are smaller.
In the image posted above.
RedView.Leading has a higher value than BlueView.trailing.
The equation is satisfied because 8 is added to BlueView.trailing.
The same would apply to the circled constraint in the image below.
superView.top is less than greyView.top because superView.top is on origin.x .
My question is are the values relative to the origin point ?
Theory of Relativity in Auto Layout
Short answer:
Yes and no. Actually more no. But most importantly: It's irrelevant!
Detailed answer:
Layout attributes are abstract descriptions of a view's position and size.
Position attributes:
top
bottom
leading
trailing
...
Size attributes:
width
height
While size attributes can describe an absolute value (e.g. view.height = 20.0) position attributes are always relative to another position attribute. That's why Apple only shows two views in their example, without any coordinate system. The equation
RedView.leading = 1.0 × BlueView.trailing + 8.0
states that RedView's leading edge is always 8.0 points to the right of BlueView's trailing edge. The origin of the underlying coordinate system doesn't matter!
Let's say we have a coordinate system ∑1 with an origin O1 and let's assume that BlueView's trailing edge is at x = 100 with respect to that origin. This would mean:
BlueView.trailing = 100
RedView.leading = 1.0 × 100 + 8.0 = 108
Now we look at a different coordinate system ∑2 with an origin O2 that's shifted by 20 points to the left, so
O2.x = O1.x – 20
O2.y = O1.y
In this coordinate system BlueView's trailing edge is at x = 120. So we get:
BlueView.trailing = 120
RedView.leading = 1.0 × 120 + 8.0 = 128
As you can see the values for the layout attributes BlueView.trailing and RedView.leading are different in ∑1 and ∑2. However, the horizontal spacing between the views is the same
RedView.leading – BlueView.trailing = 8
in both coordinate systems.
And that's the whole point of Auto Layout:
To describe the positions and sizes of views relative to each other, rather than using absolute values with respect to a particular coordinate system.
When I tell you to park your car behind your neighbor's car and leave a 1 meter gap in between, you know what to do, right? Without knowing where the road begins!
It's not important.
However – and I guess that's what made you ask the question – the system will need to "tell" the display at some point which pixels to draw for a particular view. And the pixel grid does have an absolute origin and a fixed coordinate system.
So eventually, the system will substitute the layout attributes for the outermost view (the window) before solving all the constraint equations. At that point in time your layout attributes will be relative to a particular origin (most likely the window's origin in the upper left corner, yes) but it's simply irrelevant!
Apple may choose any coordinate system they want (even a coordinate system whose origin is 50 points above the screen) and regardless of that particular system your layout will still look the same with the same set of constraints.
No, values are not relative to origin point. Forget about this.
To position them there must be some additional constraints applied to such attributes of views as:
left, right, top, bottom, leading, trailing, width, height, centerX, centerY, lastBaseline, firstBaseline, leftMargin, rightMargin, topMargin, bottomMargin, leadingMargin, trailingMargin, centerXWithinMargins, centerYWithinMargins.
Also in iOS 9 there were added diffrent kind of anchorPoints to make adding constraints easier.
Also Autolayout added localized leading and trailing attributes which position (leading is at left or right side of view) depends on Device Locale.
I would suggest the following equations:
redView.width = 0 + 1 * blueView.width
redView.height = 0 + 1 * blueView.height
redView.leading = 20 + superView.leading
blueView.trailing = -20 + superView.trailing
redView.bottom - blueView.bottom
redView.bottom = superview.bottom - 20
So it does not matter where origin is.
Everything you are asking requires knowledge of Auto Layout.
Leading, Trailing, Top, Bottom and other several constraints are applied w.r.t to the views.
Example:
RedView.leading = 1.0 x BlueView.trailing + 8.0
here, the leading constraint of RedView is applied w.r.t the BlueConstraint trailing whatever it is. i.e. RedView is placed 8 points farther than BlueView in horizontal direction.
https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/AutolayoutPG/index.html
provides a good knowledge of the auto layout constraints, in what context they are applied and the how the views layout according to them.
Also there are top layout guide, bottom layout guide, margins with respect to which you apply constraints to a view.
Read more about auto layout to get a clear understanding.
Edit:
Example:
BlueView frame: (x: 0, y: 0, width: 4, height: 2)
Now the BlueView trailing that we have is: 4
So now we are setting RedView leading as:
RedView.leading = 1.0 x BlueView.trailing + 8.0
i.e. RedView.leading = 1.0 x 4 + 8.0 = 12.0
So now the frame of RedView is: (x: 12, y: 0, width: 4, height: 2)
Also from above equation,
BlueView.trailing = RedView.leading - 8.0
i.e., BlueView.trailing = 12.0 - 8.0 = 4.0
So, the equation is valid for both RedView and BlueView.

Explain Aspect Ratio and respective terms in iOS?

I want to understand Aspect Ratio.
Here, I am setting Aspect Ratio of an UIImageView.
These are options when I click this constraint.
How this constraint works and what are "PRESETS", Reverse Multiplier and Convert to Decimal.
Thanks.
Aspect ratio constraint is used to control the width and height of a view as per a aspect ratio that you set here. There are some standard presets such as 1:1 which means width will be equal to height. Similarly other presets calculates the dimensions based on a ratio
Reverse Multiplier is just used to reverse the ratio. E.g. 4:3 will be 3:4
Convert to decimal just represents the ratio as a decimal. E.g. 4:3 will be 1.33
If you want a view to always maintain an aspect ratio then you can use this constraint. In your case if its image view and you know the aspect ratio of the image that will be set then you can set that aspect ratio as the constraint so that the image is always sized according to the image that is set to that image view,
If you select Aspect Ratio for a single item, the width of the item is
used as the numerator for the ratio, and the height is used for the
denominator. If you select Aspect Ratio for multiple items, Auto
Layout chooses the width of one of the items for the numerator and the
height of another item for the denominator. To change the initial
aspect ratio, edit the Multiplier field of the Attributes inspector
for the constraint. To change which item to use for the width or the
height, use the First Item and Second Item pop-up menus in the
Attributes inspector.
Read more here
Constraints are something like equations in maths.
Ex:
let
X- known value (20)
Y- Unknown value (?)
m- multiplier (like 2 or 3 times)
C- constant (+3 or -3)
to find Y value we use this equation.
Y = m * X + C
Y = 2 * 20 + 3
Y = 43
Constraint equation:
First Object = (Multipler * Second Object ) + constant
width = (0.5 * Height) + 20
In Aspect Ratio condition
Note : one value should be fixed ( Height or width )
A) PRESETS
1)Width = 1 * Height
Width/ Height = 1/1 (1:1)
2)Width = 3/4 * height
Width / Height = 3 / 4 (3:4)
B) REVERSE MULTIPLIER
Before Reverse
Width = 1/2 * Height (1:2)
After Reverse
Width = 2/1 * Height (2:1)
C) CONVERT TO DECIMAL
Before conversion
Width = 1/2 * Height
After Conversion
Width = 0.5 * Height (0.5)

How to get the X and Y of the edges of the screen in Swift

I've wrote this code down here but it's not working the way I want, I have only got the random position in the all view, my meaning is to get random positions on the edges of the screen. How can I do it?
let viewHeight = self.view!.bounds.height
let viewWidth = self.view!.bounds.width
randomYPosition = CGFloat(arc4random_uniform(UInt32(viewHeight)))
randomXPosition = CGFloat(arc4random_uniform(UInt32(viewWidth)))
Use the following property:
For Max:
view.frame.maxX
view.frame.maxY
For minimum:
view.frame.minX
view.frame.minY
If you really want the bounds of the screen, then you should see How to get the screen width and height in iOS?, which tells you that you need to look at the UIScreen object for its dimensions. In Swift, the code works out to:
let screenRect = UIScreen.mainScreen().bounds
let screenWidth = screenRect.size.width
let screenHeight = screenRect.size.height
That really gives you the screen width and height, but it'd be strange if the screen origin weren't at (0,0). If you want to be sure, you can add the origin's coordinates:
let screenWidth = screenRect.size.width + screenRect.origin.x
let screenHeight = screenRect.size.height + screenRect.origin.y
All that said, there's usually little reason to look at the screen itself. With iOS now supporting split screen, your app may only be using part of the screen. It'd make more sense to look at the app's window, or even just at the view controller's view. Since these are both UIViews, they both have a bounds property just like any other view.
If I got you correctly, what you want is random points which fall in the edges of the view. That means on the four sides of the view, either x or y is fixed. So here is the solution :
top wall random points( where y is fixed to 0, and varying x):
topRandomPoint = CGPointMake(CGFloat(arc4random_uniform(UInt32(viewWidth))), 0)
right side wall points ( where x is fixed to max-width (e.g 320), and varying y)
rightRandomPoint = CGPointMake(viewWidth, CGFloat(arc4random_uniform(UInt32(viewHeight))))
Bottom random points ( where y is fixed to max-height (e.g 568) and x varying)
bottomRandomPoint = CGPointMake(CGFloat(arc4random_uniform(UInt32(viewWidth))), viewHeight)
Left random points (where x is fixed to 0 and y is varying)
leftRandomPoint = CGPointMake(0, CGFloat(arc4random_uniform(UInt32(viewHeight))))
This should give you a random number in the range 0 - ViewHeight and 0 - ViewWidth respectively
CGFloat(arc4random_uniform(UInt32(0..viewHeight)))
CGFloat(arc4random_uniform(UInt32(0..viewWidth)))
Now you need to construct the position based on the 4 cases
X = 0, Y = Random (0 - ViewHeight) --> Left side
X = self.view!.bounds.width, Y = Random (0 - ViewHeight) --> Right side
X = Random (0 - ViewWidth), Y = 0 --> Bottom side
X = Random (0 - ViewWidth), Y = self.view!.bounds.width --> Top side

Resources