autolayout preventing button from moving - ios

I posted a question wondering why my UIImages were staying in the same position as in the interface builder, despite me adding the
self.non_image1_outlet.center = CGPoint(x: 211, y: 10)
self.med_image2_outlet.center = CGPoint(x: 244, y: 10)
self.image3_outlet.center = CGPoint(x: 277, y: 10)
I have switched from using images to buttons now. My issue was that no matter what CGPoints I put in the code above, the buttons would always go back to the same position as in the interface builder. I was not getting my desired position. I wanted the other buttons to move somewhere else when one of them is pressed, but again, auto layout is preventing this. The buttons quickly move to said position but "snap" back to place to the original location placed in the interface builder.
I got downvoted since I had lack of code, but i've figured out it isn't a code issue, rather auto layout. Disabling it from the file inspector, the button moved to where I wanted it to go. However, disabling auto layout messed up my whole main UI and caused a huge mess. Is there anyway to disable auto layout on a specific element rather than the whole project? The reason the button did not go to where the CGPoint specified is due to auto layout locking it in place despite me putting no constraints on it.
EDIT: Or just being able to move the UIButton to where I want it to go with auto layout active.

Any changes you make to center or frame will get reset the next time the auto layout engine does a pass.
To move your button, you either need to:
Move the button by updating the constant value of your button's layout constraints
Remove the layout constraints and set the button's position manually

I fixed the issue by re-adding proper constraints. Everything seems to works fine now.
If you are having the same issue I did, I suggest clearing all the current constraints and slowly adding the proper constraints one of by. Top, left, right, and bottom margin, as well as spacing to any other elements.

Related

Autolayout not working with Custom Keyboard, is this an Apple bug, or am I missing some settings?

In a regular app, in the initial viewController, if I add two UIHorizontalStackViews, and add two buttons to each, and set their heights to be 0.5 of the view, while setting the left, top, and right properties to 0, they behave as we expect:
However, if I do this exact same process on a custom keyboard extension that uses a viewController, I get this:
You would think that it would make each UIHorizontalStackViews take 50% of the keyboard height, but no the keyboard shrinks and the buttons get smaller.
I then tried adding one single vertical stackview, that had 4 rows of horizontalstackviews, making it have height of 1.0 of it's view, and margins of left 0, top 0, right 0, in this case, the window ended up taking far more than half of the screen, more than the custom keyboard's height is allowed to be.
Not sure if this is a bug or what. I was assuming autolayout would be adjusting the keyboard height depending on screen orientation, and phone model.

iOS: updating constraints and frame at the same time

I have in my app one UITextField on the left and one UIButton on the right. The textfield is anchored on the left at the superview (a container view) and in the right to the button.
So in the left of textfield there is a
leading space = 0 in relation of container
and on the right a
trailing space = 0 in relation of button
but if I move the button on the right way, changing the x origin value, why the textfield don't enlarge its width?
(obviously the button has its constraints about width and height and for position, but not that lock the textfield)
so if I do this
self.mybutton.frame = CGRectMake(self.mybutton.frame.origin.x+100, self.mybutton.frame.origin.y, self.mybutton.frame.size.width, self.mybutton.frame.size.height);
the button moved in the right direction but the textfield seems to doesn't enlarge its width,.
Do you know why?
Working with both Auto Layout and programmatic positioning/sizing can create a lot of headaches. Part of this is because you have created constraints in Auto Layout, which are basically "rules" that your app must follow when laying out all of it's views, and when you change the frame, bounds, or center properties you may be invalidating those rules. But since Auto Layout is not constantly recalculating the layout of your views, problems may go unnoticed until a layout recalculation is triggered.
So to answer your question, changing the frame of the button does not change the text because Auto Layout has no idea that anything has changed. Plus you haven't changed the constraints on the button so if you did call - (void) setNeedsUpdateConstraints on your text field and button, the change you are looking for won't happen. The button will move back to it's initial position, the one you set with constraints.
What you may want to do is create an IBOutlet on whatever is controlling how the button gets positioned on the x-axis (i.e. its trailing space...if that is what you are using). Then instead of doing:
self.mybutton.frame = CGRectMake(self.mybutton.frame.origin.x+100, self.mybutton.frame.origin.y, self.mybutton.frame.size.width, self.mybutton.frame.size.height);
You could do something like:
self.mybuttonXconstraint.constant = self.mybuttonXconstraint.constant + 100
[self.parentView setNeedsUpdateConstraints]
The second line is to ensure that Auto Layout knows a constraint has been changed and that it should recalculate the layout for any views involved with the parent's constraints.
This may be of interest to you as well - iOS Developer Library - Auto Layout Guide
Could you try animating the button's trailing constraint?
Like so (I changed the constraint inside an animation block for illustration purposes):
UIView.animateWithDuration(
5.0,
animations: {
self.buttonTrailingMarginConstraint.constant = 0
self.view.layoutIfNeeded() // Necessary when changing constraints.
}
)
Final result:
Git clone project: https://github.com/backslash-f/animating-constraints

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.

Swift: centering a label with another control in the way

I'm wondering if I can move a label to the center of a view even if there are other hidden controls in the way. I'm using Swift 1.2 and I'm using auto-layout for the initial position.
So I really have two questions:
How can I move a label to the center? I've found plenty of examples of moving to a particular location based on the original position. I just want the center. I tried this:
self.labelTest.center = self.view.center
Will it work 'over' hidden controls or do I have to move them too? i.e., to get them out of the way
Thanks
self.labelTest.center = self.view.center
This instruction won't be affected by the existence of any other views on your self.view if autolayout is off. However if autolayout is enabled depending on what constraints you've set they may interfere with the positioning of your views. So either turn off AutoLayout or ensure the constraints don't hinder your view being centered.

How to slide content over with AutoLayout

I have a messaging view where the user can select emoticons to add to the message. I have a bar above the keyboard where the user can enter their message. It looks something like this: H:|-[UIButton: emoticon]-[UITextField]-[UIButton: send]|
Now I've tried to slide all these over by setting their left constraint to constraint.constant -= screenWidth, but this didn't seem to work, as I got loads of "Could not satisfy constraints" messages in the log and none of them moved. I also had the problem of not knowing where to put the emoticons (it's a bar of UIButton with one emoji each).
Is there a way to do this in a simple way?
If I understand what you're doing right (you're sparse on the details), your problem is that your constraints are still pinned to the start and end.
You will probably need to remove the last item's right constraint before you can scroll anything.
That said, what I usually do in cases like this is wrap everything that's supposed to scroll in a plain UIView. Then I can keep their internal constraints the same, and only the UIView is pinned to the left and right of its superview. To scroll, I simply add a width constraint with the current width, remove the right constraint, and then subtract from the left constraint's constant to scroll it off screen.
That extra view gives me a guarantee that everything stays the size and location it had at the beginning of the animation, and might even allow me to optimize the animation (e.g. I can rasterize the view before I scroll it out, and UIKit then only has to move one layer).

Resources