Autolayout Dumbness (Mine)? - ios

I'm using auto layout in one of my projects and am having trouble with what I thought should be a trivial task.
As an example, I have two text boxes below each other. I have created a vertical spacing constraint between the two, of 5 points.
I would expect that if i move the top text box (using setFrame), the constraint would mean that the bottom one would automatically move with it to enforce the constraint?
Is my thinking correct? or am I using auto layout in a way that it was not meant to. ie. I have misunderstood its purpose. Or should I be moving the top text box using a different manner other than setFrame?
Any input would be great. Thanks in advance :-)
PS. I have played around with using: setTranslatesAutoresizingMaskIntoConstraints which seems to work. However, this doesn't seem like the proper way to do this. My initial thoughts are that auto layout is supposed to handle size/position relationships with little code, in this case, i would expect it would be handled with zero code.

You can't use setFrame to do that. Auto-layout decides the frame. If you change it after the fact the constraints aren't automatically updated.
You could get a reference to the constraint that decides the Y position (either when you create it programmatically or using an IBOutlet) of the top box and change its value. That would trigger an update to recompute the position of everything and run layout again.
You would do that by changing the value of the constant property on the NSLayoutConstraint object.
Reference Docs Here

Related

Auto layout and animation

in my program I have 14 different buttons with a letter each. And every single button is connected to each other with auto layout. So there is crazy lots of constraints. See first image for explanation:
But I want to be able to move every single button back and forth through UIAnimation without messing up the whole auto layout setup. See second image for explanation, what I want to do:
Now the code I currently use to get these animation:
self.letterA.translatesAutoresizingMaskIntoConstraints = YES;
[UIView animateWithDuration:0.2 animations:^{
[letterA setFrame:CGRectMake(x, y, width, height)];
}];
Now the program works perfectly! Absolutely no problems at all! But the only "problem" is this code generates this message in the console:
Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
And this warning/error/problem goes on and on and on several times, every single time a UIButton is moved. Now what should I do?
Can I ignore the Unable to simultaneously satisfy constraints? Or will that cause trouble down the road?
If not, how to fix it? And since there are crazy amounts of constraints involved, how can it be fixed without editing every single constrain?
I would very much like to keep animating using setFrame:
To your points:
"Can I ignore the Unable to simultaneously satisfy constraints warning"
No. It's a really bad idea to ignore this, even if the UI appears more or less as you want it to even with the warning. It means that the system is deciding how to render your layout, because the instructions you have supplied are contradictory. It has analyzed the constraints you have provided and found a way to create a consistent layout by breaking one or several of them. There is no guarantee that it will decide to break the same constraints on different screen sizes or OS versions. Ignoring this warning massively increases the chance of UI bugs.
I'd rethink the whole way this UI is designed. IB/Storyboard Autolayout works well for UIs up to a certain level of complexity. This UI looks to be slightly beyond that level of complexity - if the tiles didn't need to move, it would be fine. As they do, programmatic autolayout may make things simpler.
The approach I'd take would be as follows.
a. Create a tile object, which exposes NSLayoutConstraint properties for top, left, width and height constraints. (These constraints would be added on the superview, but also stored on the tile itself).
b. Set up the views using a factory object method taking the starting position offset, width and height of the new tile as parameters. Use these values to set up the constraints on each tile independently. Don't constrain the tiles to each other at all - all constraints should be either internal (width,height) or relative to the superview (x,y). This means that when you animate changes only one tile is affected. You actually have more constraints, but they are in code and therefore easier to manage.
c). Use UIView animations to move the tiles around and resize them using the constraints on the tiles. You can store the initial frames for each tile position and use those values to determine the target constraint values. You should easily be able to resize the position and size of the tiles in this way.
d). Apple's API for NSLayoutConstraint is a bit verbose and ugly. Consider using Masonry, a nicer Autolayout DSL, in order to keep your code clean.
You can continue to use -setFrame:, as long as you don't use Autolayout - the two approaches just don't play well together. If you want your app to run on more than one screen size, you need to use Autolayout, or else recalculate every frame and offset dynamically in code. If you don't (maybe it's an iPad app and you don't care about the Pro, then just use -setFrame:). But, on balance, I'd advise biting the bullet and just learning Autolayout
If your using auto layout you should set the translateAutoResizingMask to false otherwise you will keep getting this error. Instead you should be setting the new location using constraints only before the animation block then call layoutIfNeeded in the animation block. As you are setting the constraints in interface builder that has the effect of setting the translateAutoResizingMaskToConstraints to false automatically.

What if I use "Add missing constraints" option from storyboard, for assigning constraints in storyboard?

My question is that, can I trust on
Resolve autolayout issues’ - “Add missing constraints”
option(as in the attached Screen shot), which automatically adds constraints to the objects present in the storyboard?
I used this and tried running the app in all screen formats and it works fine, so can I continue using this or is it wrong to consider “Add missing constraints” for the constraint design. I’m new to auto layout and any kind of response, explaining this concept will be appreciated. Thanks
Utilizing the automatic constraint system is a bad idea. Most of the time, it won't work dynamically for all screen sizes. It generally adds constraints so objects appear correct in the current resolution you're designing in.
For example, it may pin a label you have placed in the center of an iPhone screen based on the distance from the left edge of the screen instead of the X value. That distance from the edge is going to stay the same when you run it on an iPad and it's going to be significantly off-center to satisfy that constraint.
However, depending on the situation, it could pin them correctly (IE leading edges to the super view instead of a constant). You can use the automatic constraint system for suggestions to reference what you need to add still, but I would not rely on it for dynamic UI.
Spend your time learning autolayout instead of throwing darts in the dark, it's really not as intimidating as it seems!
No you should not trust. Add missing constraints will add constraints that are missing. It will not add constraints that's your design actually want.
So I suggest you to understand what constraint you'll require to complete UI.
`For every control, Compiler need to know its : x,y,width and height.
For example : You drag & drop UILabel on your xib. Now you add top space constraint. So compiler will give warning. Need constraint for : X position.
On above example width and height will take according to text of label. Now you had given top space so its y position is known.
But for X you didn't give any constraint. In this case if you use Add missing constraints. compiler will add constraint for x position according to your placement. It may be your require constraint or may be not.
No iT just add the required constant so may be they are fixed so remove all constraints and try again.
Just like what the others say, "Add Missing Contraints" will always give the result of the layout that you desired. It's best that you learn to add constraints manually. But, there are times that you can be lazy for a couple of seconds by using that method but only for very simple layout.
I'll just share my thoughts about when should we use this method.
I use "Add Missing Constraints" when:
My layout is very much simple, it's like I know that when I do it automatically will yield the same result as doing it manually. This help saves a lot of time.
I am setting up constraints manually, but sometimes I don't know what constraints I am missing because the object that I am setting the constraints still shows red lines(missing constraints). This is just my purpose of learning.

Layout changing when running the app

I've been trying for days to make one layout of my app to work well, and after days of learning and mistakes I still can't get the table cell layout to look how I want it to be.
This is how my cell .xib looks like in the editor:
http://i.stack.imgur.com/VEr3r.png
And this is how my app looks like when running with suggested constraints:
http://i.stack.imgur.com/wiK1f.png
Why is that? How I can find my mistake and make the layout like it supposed to be, in the view?
Suggested constraints are rarely what I actually wanted to see.
For each label with fixed text, lock the horizontal and vertical positions either to the view or to the next adjacent item.
For imageViews, choose the size you want and lock the height and width.
For labels that you will be dynamically changing the text on, pick a size that will hold the longest string and lock the width. You'll need a vertical position constraint.
You have many options to simplify your layout.
you can use the stakview or create a static UITableView and insert your component inside the cells and enter the Constraint. excellent tutorial http://www.runtimecrash.com/2015/09/17/exploring-uistackview/

Difference between UIView.layoutMargins and AlignmentRect

I'm figuring out (again) how to set the margin for a custom UIView instance. From what I recall I had to set the AlignmentRect via the alignmentRectInsets method. But that did not worked with auto layout.
Searching on google I found that there is another property called layoutMargins.
So the question is what does layoutMargins and alignmentRect do ? Do they affect each other? Totally different things ?
layoutMargins determines how things inside of the view are positioned with auto layout. Usually this is used to keep objects a specific distance away from the edges of the view.
alignmentRectInsets is for telling objects outside of your custom view how they should align with it. For example, you might have a view with a wavy or angled top. Aligning other objects with the top of the view may not look quite right, so you might set an inset on the top alignment to compensate.
You probably care about the layoutMargins. I've never actually seen anyone use alignmentRectInsets.

Animating views constrained with auto layout

Just for fun I started to play with animations after successfully applying them to some basic background color changes. I have some different images on my "welcome/splash" view that I would like to animate. One image should appear from the bottom, another from the top and so on.
I immediately ran into trouble since I am using auto layout it was not that easy as animating background colors. I found this post How do I animate constraint changes? and after doing what was described at least my image was animating. However, is it correct that the console window should be filled with warnings/info/errors about constraint violations? Also, animating the vertical position of one image causes all the other image to animate too, probably because of some constraint relations.
How are you supposed to deal with that? when animating the "Bottom layout attribute" with a new constant value I expect only the view it belongs to animate, not the whole screen.
And how are you supposed to refer to the constraints? By outlets?
I am creating my views and constraints in storyboard. I deleted my code for animating the image views since it was just a mess. But whats done with the button and textfields in this tutorial is pretty much what I am trying to do with my images. Without animating one image causing the whole view to animate with it. http://www.raywenderlich.com/113674/ios-animation-tutorial-getting-started
However, is it correct that the console window should be filled with warnings/info/errors about constraint violations?
Learning Auto layout can be a challenge which will fill your days with such warnings/info/errors about constraints. Many iOS developer's struggle with Auto Layout at first. Auto layout is an addition to the layout process. The issue here is how are you going to deal with them. I suggest reading the Apple Auto Layout Guide, it contains a section on debugging. Also look at the Debugging Tricks and Tips section.
Here's a great article explaining more of the concepts behind Auto layout.
Build a simply app that has only one view and a subview, so that you can reduce the noise around layout constraint errors in more complicated layouts.
Here is a code snippet of how to animate a constraint.
if myViewTrailingConstraint.constant == -2 {
myViewTrailingConstraint.constant = 200
} else {
myViewTrailingConstraint.constant = -2
}
UIView.animateWithDuration(0.3,
animations: {
self.view.layoutIfNeeded()
},
completion: nil)
How are you supposed to deal with that?
Auto layout is an inter connected system of relationships between your views. A constraint represents a relationship. So you really need to think through your view's layout and plan your constraints first. Why? because if you plan to animate certain views you need to need to make sure that the constraint constant you are going to change will effect only that view in question.
And how are you supposed to refer to the constraints? By outlets?
You can create constraints solely in code or with the interface builder (outlets). I would suggest that you start with interface builder as even when you are comfortable working in code, it is useful and time saving to be able to do your initial layout in interface builder - so learn to use both.
Warnings are not normal - you have to solve them to avoid strange effects.
If animating a constraint value of one image moves other images, then indeed you must have some constraints in place that also change - e.g "equal width" constraints or such. Normally it just works - if it doesn't, you have to show the warnings you get and the constraints you set in order for someone to see what is going wrong.

Resources