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.
Related
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.
I've got a UITableViewCell that has a child view, and within it an image view and a label. I am wanting to use the child view as a means of giving some margin around the contents of the cell, thus giving me margins inbetween cells. This seemed to be the way a lot of people online recommended doing it.
I've set up my constraints as shown below:
I have performed a Update Frames on all views in the view controller. The story board shows it exactly as I'm expecting it to be on the phone. When I run it on the phone though, I get this...
I'm completely baffled at this point. I've spent two days of reading and trying to layout a simple UITableViewCell and clearly don't have a good understanding of how auto-layout works still.
I've even just laid everything out along the suggested boundaries (the blue lines) and then told the storyboard to generate suggested constraints. At which point the content of the cell just sent with 50% of it off the right side of the screen and un-viewable.
So two questions:
The storyboard more often than not shows me something that is not accurately represented on my actual device. Is this fairly common in iOS development? Should I not be relying at all on the storyboard auto-layout representation?
What do I have to do to these constraints in order to get the cells to layout on my device, like it is shown in my storyboard at this time? What constraints am I setting wrong?
Storyboard doesn't display the content according to any device by default. You can set it to your current device in its size properties(by default it is "Inferred"). Constraints are used to display the views equal on all devices. They automatically adjust UIelements according to display size. So if you want your app to run on devices of different sizes you have to rely on constraints.
I think you are setting too many constraints. Happens if you are new to auto layout. Try reading this guide. Its very helpful.
I´m pretty new to Xcode and playing around with some techniques.
For testing, i am writing an app where i have a detailViewController with three views within.
As soon as i assign constraints to one of the views the layout gets really strange. No matter if i center horizontally or set border distance, the view seems somehow to vanish and the components within the view are placed somehow.
Any idea what i´m doing wrong?
Sure, you need to follow these basic rules. Checkout the auto layout guide. Each view from the top of the scene to the bottom should have constraints (also constraints should exist from side-to-side if you want expansion and contraction, or have height/width if those are important to maintain). Most times you will need to have at least four constraints per view. The auto layout errors will not go away until all the views have constraints applied and adhere to the simple rules I mentioned above.
Im starting to experiment with storyboard. As you can see I have chosen the storyboard size to be height=regular and width=compact, which says “For all iPhones in portrait”.
The simulator I am using is iPhone6 however when I run everything is slightly off to the right.
Can someone explain what is happening or what I am missing?
The problem is that (as described in the comments) you are positioning the views without AutoLayout. When you just drag and drop the views, it's actually setting the frame's positions and sizes. The main problem with this approach is that it doesn't set the position and size in a proportional and related manner, taking in consideration the container. This is why you're getting the view at the current position. If you run in another simulator, maybe you can get the correct position, or maybe not. What you can do to change this is apply auto layout constraints to those views. There's a special constraint to center views horizontally. With autoLayout you can go further, specifying relation between one or more views, and those views not necessarily need have the same container view.
One quick example:
Notes:
I'm using universal storyboard to take those screenshots. It's more flexible and with AL you don't necessarily have to concern yourself with the size, as views adjust themselves depending on the constraints applied to.
EDIT:
https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/Introduction/Introduction.html
This is a link to auto layout guide provided by apple, a great tutorial on how to get your hands dirty in this little world.
I have been struggling with IB and auto layout and figure there must be an easier way to create a simple scrollable form with multiple fields on it. The width can adjust to the device screen width (or in the case of the iPad to the details view of a split view.
The basic layout is simple a label and underneath a field (in some cases the field must have a minimum height) repeated for each attribute.
I think I must be doing something completely stupid or IB's autolayout is hopeless, I suspect the former. In any event whatever I do in IB fields just adopt whatever constraints they feel like it seems. Even when I set a constrain it seem IB just replaces it sometimes.
Currently I am using a view with a fixed height and width that fits the screen and laying out fields on this form, however its a complete nightmare having to pin every field in almost every direction. And then IB complains about a million constraints that it can't satisfy.
Hopefully someone has a better way of doing this they are willing to share - perhaps it might be best just to write some code to set up the constraints rather than relying on IB ?
Thanks
You are right UIScrollView and autolayout is not clear at first look.
You have to understand that when you are adding layout constraints for a view inside scroll view, the superview is content view of scroll (not the view of the UIScrollView) that can be more or less then current view of the ScrollView in IB.