Auto Layout: understanding the behavior of attributes and items - ios

I use Auto Layout programmatically a lot but there are still two things that I do not understand.
What is the difference between leading and left attribute/anchor and between trailing and right attribute/anchor?
To me there seem to be the same but according to the docs:
However, Auto Layout does not allow constraints that mix leading and trailing attributes with left or right attributes. As a result, this constraint crashes at runtime.
The order of the the items inside the NSLayoutConstraint does not matter for the Auto Layout system at all, am I right? (At least for .Equal relation.)
Do not get confused about the attributes for each individual item, I'm aware of that.

Left and right are always left and right.
Leading and trailing are not. From Working with Constraints in Interface Builder:
If you lay out your views using leading and trailing constraints, the views automatically flip positions when switching between left-to-right languages (like English) and right-to-left languages (like Arabic). However, some interface elements should not change their position based on the reading direction. For example, buttons that are based on physical directions (up, down, left, and right) should always stay in the same relative orientation.
The order of items for an equal relation is irrelevant.

The difference between leading and left is important when taking into account RTL languages, such as Hebrew. In that case, the UI is inverted to complement text direction, and so are the UI elements with constraints. In this case, leading means the side where text starts. left is always left, for text direction agnostic UIs, such as media playback controls.
The order constraints are placed in does not matter. If there are conflicting constraints, the behavior is undefined.

Related

iOS - Swift 4 - Constraints for text fields side by side

I Have a view like so:
And I am trying to add constraints so the text fields are side by side so the auto looks the same no matter the device width, how would I do that?
I have tried the following for all 6 of them:
But it ends up looking like this:
What am I doing wrong?
Ctrl drag from the description TextField to vendor TextField and select Equal Widths from popup
You can also use a vertical stackView where each row is a horizontal 1 with distribution set to Equal spacing and drag the text fields to it that will be more easier
Well, let's look at what we know about the horizontal axis (I assume you've got the vertical axis taken care of). There are two text fields; call them Left and Right. We know these things:
Where Left's leading edge must be
Where Right's trailing edge must be
The distance between Left's trailing and edge and Right's leading edge
The relationship between Left's width and Right's width, i.e. they are equal
Ta-daa:
(A UIStackView would construct these same constraints for you, but in a simple situation like this it's probably more trouble than it's worth.)
There are many ways to do it
I give you two but recommend the first one in your case.
First :
Define a constraint by draging one of your UITextFiled to the other one and set it to “Equal Widths”
You may also be able to define a percentage for each (60-40%) if you like.
Second :
Define a constraint like above (draging) And define a relative ratio (0.5) for UITextField width against its superview. Do it for the other one. You need to go to Object Inspector Tab and change the values if needed (so this requires two constraints, one for each UITextField as each of them are relative to the their superview) this is also a little bit slower than the first approach since margins should be defined with priority.

Xcode 8 : Auto layout Leading & Trailing

I started iOS development a week ago and I'm currently learning AutoLayout. and sadly I can't wrap my head around the Leading & Trailing constraints and when to use them, I don't even understand them at all. I have done some research and I'm just actually more confused now. Can someone give some examples?
This definition is form the Apple website:
The values increase as you move towards the trailing edge. For a
left-to-right layout directions, the values increase as you move to
the right. For a right-to-left layout direction, the values increase
as you move left.
https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/AutolayoutPG/AnatomyofaConstraint.html
Thanks
TL;DR
They couldn't just name it left and right because it had to make sense in both layout orientations: left-to-right and right-to-left. Hence Trailing and Leading.
Longer Answer
I think the question you're asking yourself is why the heck Apple is not just naming it left and right. What's with the trailing and leading.
The reason behind this is that there might be 2 different layouts. Starting with iOS 9, the UI layout for left-to-right languages (like English) is.. well left-to-right. But in case of Arabic for example, it's right-to-left.
However Autolayout is smart enough that you don't need to setup your layout twice for these 2 types of layouts. You just set it up once and the system auto-inverts it in case your app supports right-to-left languages.
For this answer, ignore languages like Arabic and Hebrew that flow right to left. I'm going to answer for the majority of languages that flow left to right.
For those languages, the "leading" constraint determines the space on the left of an object, and the "trailing" constraint determines the space on the right side. (A good mnemonic for this is that left and leading both start with "L".)
For languages that flow the opposite way, the sides are switched, but the "leading" still pins an object to the leading edge (The side where you start reading.)
Leading means the starting point of the view and trailing means the ending point of the view.
For example, if a view has a frame (x: 0, y: 0, width: 100, height: 100) its leading will me 0 and trailing will be 100.
So if you move right from the leading the distance between the leading and the point moved will increase and similarly this happens in case of trailing.
This was covered (briefly) in one of the WWDC 2015 videos on the Mysteries of Autolayout (I think it was part 1 but both are worth watching).
Left and Right constraints are absolute, they will always refer to the left/right of the screen or the control. Leading and trailing constraints are affected by the device locale; In locales where the reading direction is left to right (English, French, Spanish and so on) leading & left (and trailing & right) can be used interchangeably. In locales where the reading direction is right to left (e.g Hebrew) then 'leading' will be the right side and 'trailing' will be the left side.
The advice in the video was you should almost always use leading/trailing rather than left/right unless you have a specific requirement for absolute left/right.
Consider the typical 'form' of a label and a text field. If you use leading/trailing constraints then you will get the label on the left and text field on the right for an English locale and label on the right, text field on the left for a Hebrew locale.
If you made a children's app where you were teaching left from right and you always wanted the 'left' button on the left of the screen then left/right constraints would be appropriate.
Check the original answer here: Difference between leftAnchor and leadingAnchor?

iOS Localizations mess up the UI

I have an iOS Application that supports different languages, which uses LTR Storyboard and RTL Storyboard, and reads from Plists. When I run the app on my Device with English iOS Version, everything looks perfect when switching between the languages. But when I change the iPhone OS Language to RTL languages. The UI is messed up.
This happens especially when I enable Localizations to change the app name on home screen.
Any idea why does that happen?
The whole menu is messed up for example, it's to the left side while it should be to the right side, and the menu items icons must be to the left and the labels to the right.
RTL Language on LTR iOS Language Device i.e English
RTL Language on RTL iOS Language Device
This is because you are use leading and trailing constraint.
In a LTR environment leading means left while in an RTL environment, leading means right.
This is Apple way of helpings us to deal with RTL/LTR easily :[ in your case, not so much...
To disable this behaviour, change the semantic attribute of your views.
Semantic Content
If you lay out your views using leading and trailing constraints, the
views automatically flip positions when switching between
left-to-right languages (like English) and right-to-left languages
(like Arabic). However, some interface elements should not change
their position based on the reading direction. For example, buttons
that are based on physical directions (up, down, left, and right)
should always stay in the same relative orientation.
The view’s semanticContentAttribute property determines whether the
view’s content should flip when switching between left-to-right and
right-to-left languages.
In interface builder, set the Semantic option in the Attribute
inspector. If the value is Unspecified, the view’s content flips with
the reading direction. If it is set to Spatial, Playback, or Force
Left-to-Right, the content is always laid out with the leading edges
to the left and trailing edges to the right. Force Right-to-Left
always lays out the content with the leading edges to the right and
the trailing edges to the left.
Assuming that you are already using Auto Layout,
Make sure you have done the following
Remove fixed width constraints. Allow views that display localized text to resize. If you use fixed width constraints, localized text may appear cropped in some languages.
Use intrinsic content sizes. The default behavior for text fields and labels is to resize automatically. If a view is not adjusting to the size of localized text, select the view and choose Editor > Size To Fit Content.
Use leading and trailing attributes. When adding constraints, use the attributes leading and trailing for horizontal constraints. For left-to-right languages, such as English, the attributes leading and trailing are equivalent to left and right. For right-to-left language, such as Hebrew or Arabic, leading and trailing are equivalent to right and left. The leading and trailing attributes are the default values for horizontal constraints.
Pin views to adjacent views. Pinning causes a domino effect. When one view resizes to fit localized text, other views do the same. Otherwise, views may overlap in some languages.
Constantly test your layout changes. Test your app using different language settings, as described in Testing Your Internationalized App.
Don’t set the minimum size or maximum size of a window. Let the window and its content view adjust to the size of the containing views, which may change when the language changes.
See more
Probably a matters of constraints. In the storyboard, you can use the preview editor to get a .. well.. preview, of your UI in diffrent device size in different language.

Auto layout space between elements relative to screen height [duplicate]

I understand the old Struts and Springs method of aligning, sizing and distributing views in Interface Builder. However, I cannot seem to figure out how to evenly distribute views using auto layout with Xcode 5. There was a way to do it using Xcode 4, but that option is gone.
I have 7 buttons arranged in a vertical stack. On a 3.5" layout, it looks great. When I preview the screen in the 4" layout, all of the buttons remain tightly packed and there is a large amount of space below the last button.
I want them to stay the same height, but I want the space between them to be able flex so they can spread out across the screen.
I've been able to get the height of the buttons to flex and fill the space, but that is not my desired behavior. I would like to learn how to use Auto Layout to replace my old Springs behavior, but I can't seem to find any way to do it through Interface Builder.
I'm ok with the top button either being a fixed space from the top edge or a proportional space from the top edge, likewise for the bottom button and the bottom edge. Those are less important to me, I'm good with either.
But I really need to figure out how to evenly distribute the extra space between each of the items in the view.
EDIT Note that in iOS 9 this technique will become unnecessary, because a UIStackView will perform distribution automatically. I'll add another answer explaining how that works.
How to Perform Even Distribution Using Autolayout
The simplest way to do this in Interface Builder alone (rather than constructing constraints in code) is to use "spacer" views:
Position the top and bottom buttons absolutely.
Place spacer views between all the buttons. Use constraints to position them horizontally (centering them horizontally is simplest) and to set their widths.
Make constraints between each button and the spacer view above and below it, with a Constant of 0.
Now select all the spacer views and set their heights to be equal.
The first screen shot shows me setting this up in IB:
I have deliberately not corrected for the "misplaced views" because I want you to see what it looks like while I'm designing the constraints. Here's the result on both a 4 inch and a 3.5 inch screen:
I have left the spacer views black, just to show you how this technique works, but of course in real life you would make them transparent and hence invisible! So the user sees just your buttons, evenly distributed on either height of screen.
The reason for the use of this technique is that although the notion of equality performs the distribution of values you are asking for, constraints can apply equality only between aspects of views; thus we need the extra views (the spacer views) so that we have things we can make equal to other things (here, the heights of the spacer views).
Other Approaches
Obviously, a more flexible approach is to assign the constraints in code. This may sound daunting, but there's a lot of third-party code out there to help you, such as this sort of thing.
For example, if we have a (possibly invisible) superview whose height acts as a boundary to dictate maximum vertical distribution of our four buttons, we can pin their tops to the vertical center of that superview with a constant of 0 but a multiplier of 0.000001, 0.666667, 1.33333, and 2.0 respectively (if we have four buttons); now the buttons will stay vertically distributed even as the superview changes size in response to screen height or whatever. [In Xcode 5.1, it will be possible to set that up in Interface Builder, but in earlier versions of Xcode it is not possible.]
In iOS 9 / Xcode 7 this problem will be trivially solved in IB. Simply select the buttons (or whatever it is you want to distribute vertically) and choose Editor > Embed In > Stack View. Then you simply configure the stack view:
Provide constraints that position and size the stack view itself. For example, pin the four edges of the stack view to the four edges of its superview.
Set the stack view's attributes. In this case we want Vertical axis, Fill alignment, Equal Spacing distribution.
That's all! However, you may be curious about how this works, because it is still possible to do the same thing manually in code. A stack view performs distribution, not by inserting spacer views, but by inserting spacer guides. A guide (a UILayoutGuide) is a lightweight object that behaves like a view for purposes of layout constraints, but is not a view and therefore doesn't have to be made invisible and doesn't carry any of the overhead of a view.
To illustrate, I'll do in code what the stack view is doing. Presume we have four views to distribute vertically. We assign them constraints for everything but their distribution:
They all have absolute height constraints
Their left is pinned to the superview's left, and their right is pinned to the superview's right
The top view's top is pinned to the superview's top, and the bottom view's bottom is pinned to the superview's bottom
Now, presume we have references to the four views as views, an array. Then:
let guides = [UILayoutGuide(), UILayoutGuide(), UILayoutGuide()]
for guide in guides {
self.view.addLayoutGuide(guide)
}
NSLayoutConstraint.activateConstraints([
// guide heights are equal
guides[1].heightAnchor.constraintEqualToAnchor(guides[0].heightAnchor),
guides[2].heightAnchor.constraintEqualToAnchor(guides[0].heightAnchor),
// guide widths are arbitrary, let's say 10
guides[0].widthAnchor.constraintEqualToConstant(10),
guides[1].widthAnchor.constraintEqualToConstant(10),
guides[2].widthAnchor.constraintEqualToConstant(10),
// guide left is arbitrary, let's say superview margin
guides[0].leftAnchor.constraintEqualToAnchor(self.view.leftAnchor),
guides[1].leftAnchor.constraintEqualToAnchor(self.view.leftAnchor),
guides[2].leftAnchor.constraintEqualToAnchor(self.view.leftAnchor),
// bottom of each view is top of following guide
views[0].bottomAnchor.constraintEqualToAnchor(guides[0].topAnchor),
views[1].bottomAnchor.constraintEqualToAnchor(guides[1].topAnchor),
views[2].bottomAnchor.constraintEqualToAnchor(guides[2].topAnchor),
// top of each view is bottom of preceding guide
views[1].topAnchor.constraintEqualToAnchor(guides[0].bottomAnchor),
views[2].topAnchor.constraintEqualToAnchor(guides[1].bottomAnchor),
views[3].topAnchor.constraintEqualToAnchor(guides[2].bottomAnchor)
])
(Obviously I could make that code cuter and shorter using loops, but I have deliberately unrolled the loops for clarity, so that you can see the pattern and the technique.)

Auto Layout inverts views horizontally iOS

I haven’t been able to pinpoint the cause of an issue i’m having , regarding our company project.
I have notice that in all the auto layout views in the project , the views that appear to be attached to a specific side in interface builder,
are presented on the opposite side after the build.
I.e when i am adding a view to a storyboard view controller, than creating an horizontal space constraint to it’s superview leading margin (left side) it appears ok on interface builder and the preview, but after the build, it appears to be inverted on simulator/device , the view has the same horizontal space but to the opposite side ( right side on this example).
The same issue happens to all the views that are already were on the app (the views that supposed to be on the right side appear to be on the left side and vice versa )
I spend hours to figure out what cause this invert with out any success (the issue happens only in our project), i even tried to change the project definitions according to a new one.
I’ll appreciate if you will be able to help me on this matter.
I'am adding the screenshot of the view in interface builder, the preview and the simulator
There are two kinds of horizontal constraint — universal and language-bound.
The universal constraints are called Left and Right. The meanings of these constraints never change.
The language-bound constraints are called Leading and Trailing. Their meaning depends on the language environment in which the app is running. If the language is like English, Leading is left and Trailing is right; but if the language is like Arabic or Hebrew, which are written from right to left, Leading is right and Trailing is left. This allows labels to be constructed that work correctly regardless of writing direction.
This distinction is drawn in Interface Builder with the "Respect language direction" menu item; to get the universal Left-Right constraints, uncheck it:
So, you may be using Leading and Trailing correctly and appropriately for some views, but it sounds from your complaint as if you have accidentally used Leading and Trailing for some views where you meant to use Left and Right.
It happened when you have Right-to-left system language, for example hebrew or arabic. It's default Apple feature.
If you change system language to English everything should be ok.

Resources