Moving Views with Constraints

Moving views with constraints

Yes, no issue when you change the constants. The thing here is that you have to set your constraint appropriately.

Let's consider an example.

I have a UIView in Storyboard and I would like to change its width. Its default width is 1024.

After some animation, We will change it's width to 900.

Follow steps below to achieve this:

  1. Select UIView in which we want to update constraints. Here we need to update width, So we will add a constraint for width.

Sample Image


  1. Now we can see new constraint added to UIView.

Sample Image


  1. Click on that constraint. It will show constraint properties. Here now we want to decrease width from 1024 to 900, So that in constraint property change Relation property to Less Than or Equal. Similarly, if you like to increase width from 1024 then Relation will be Greater Than or Equal.

Sample Image


  1. Now create an IBOutlet variable for NSLayoutConstraint and connect it with above width constraint.

  2. Change width constant

Swift 5.0

@IBOutlet weak var viewWidthConstraint : NSLayoutConstraint!

func reduceWidth() {
// Reduce width of view.
UIView.animate(withDuration: 0.35, animations: { () -> Void in
self.viewWidthConstraint.constant = 900
self.view.layoutIfNeeded()
})
}

func normalWidth() {
// Change to the default width of view.
UIView.animate(withDuration: 0.35, animations: { () -> Void in
self.viewWidthConstraint.constant = 1024
self.view.layoutIfNeeded()
})
}

Objective C

@property (weak, nonatomic) IBOutlet NSLayoutConstraint     *viewWidthConstraint; 

- (void) reduceWidth {
// Reduce width of view.
[UIView animateWithDuration:0.35f animations:^{
self.viewWidthConstraint.constant = 900;
[self.view layoutIfNeeded];
}];
}

- (void) normalWidth {
// Change to default width of view.
[UIView animateWithDuration:0.35f animations:^{
self.viewWidthConstraint.constant = 1024;
[self.view layoutIfNeeded];
}];
}

Animating/Moving views under usage of Autolayout

You must change the constraints if you are using autoLayout. The way that is suggested is to make an outlet in your view controller of the constraint, then you change the constant of the constraint. If you have the time i would definitely recommend going here and watching "Auto Layout by Example" or "Best Practices for Mastering Auto Layout". They helped me out a lot. I guess the point to take away is that with autoLayout, you no longer think in terms of frames. So setting the center just doesnt work with auto layout. It's all about how views are related to each other.

Move view with layout constraints

Create an outlet to the top constraint. When you want the animation to run, set the top constraint's constant to the end value that you want, then, in the animation block, simply call layoutIfNeeded().

How to use Auto Layout to move other views when a view is hidden?

It is possible, but you'll have to do a little extra work. There are a couple conceptual things to get out of the way first:

  • Hidden views, even though they don't draw, still participate in Auto Layout and usually retain their frames, leaving other related views in their places.
  • When removing a view from its superview, all related constraints are also removed from that view hierarchy.

In your case, this likely means:

  • If you set your left view to be hidden, the labels stay in place, since that left view is still taking up space (even though it's not visible).
  • If you remove your left view, your labels will probably be left ambiguously constrained, since you no longer have constraints for your labels' left edges.

What you need to do is judiciously over-constrain your labels. Leave your existing constraints (10pts space to the other view) alone, but add another constraint: make your labels' left edges 10pts away from their superview's left edge with a non-required priority (the default high priority will probably work well).

Then, when you want them to move left, remove the left view altogether. The mandatory 10pt constraint to the left view will disappear along with the view it relates to, and you'll be left with just a high-priority constraint that the labels be 10pts away from their superview. On the next layout pass, this should cause them to expand left until they fill the width of the superview but for your spacing around the edges.

One important caveat: if you ever want your left view back in the picture, not only do you have to add it back into the view hierarchy, but you also have to reestablish all its constraints at the same time. This means you need a way to put your 10pt spacing constraint between the view and its labels back whenever that view is shown again.

What is the proper way of animate views when constraints applied?

The problem here, is that NSLayoutConstraint toggling works like properties in the sense that they are nothing but values which can be switched on/off, and alternated by playing with this toggling and other references to other possible values they can have. There's no real way of going around this that I know of unfortunately, and in fact i myself have built a small library similar to Anima, and it works rather well if you respect the NSLayoutConstraints' nature.

The proof of this is that under the hood of this Anima library, it's simply storing the animation points declared inside of the chain (inside Enum values in fact), and applying them as the animation moves along. Regardless, you should never re-set translatesAutoResizingMaskIntoConstraints to true when working with NSLayoutConstraints.
The second reason for this is that Constraints are the basis for all iOS frame operations, including .frame, and animations (which is why Anima works so well from the looks of it).
I wrote a post on this recently, but as I explain by referencing Apple:

Your problem is that when translatesAutoresizingMaskIntoConstraints is
called, methods like .frame or .frame.size are ignored/overriden
(depending on when you use them, before or after
translatesAutoresizingMaskIntoConstraints). As described by Apple:

Note that the autoresizing mask constraints fully specify the view’s
size and position; therefore, you cannot add additional constraints to
modify this size or position without introducing conflicts. If you
want to use Auto Layout to dynamically calculate the size and position
of your view, you must set this property to false, and then provide a
non ambiguous, nonconflicting set of constraints for the view.

UPDATED
Otherwise, try not to set translatesAutoResizingMaskIntoConstraints to true with these views, by doing that you basically tell your controller to ignore your constraints, and to try to apply constraints based on the .frame or .frame.size or position values set on the UIView. Thus, making your custom constraints obsolete. If by stopping this, you still get the issue, it's probably a constraint value issue, of which i can't give you much more advice without any code unfortunately.

How to manage constraints of movable views in iOS?

Instead of changing the frame, you could animate the change of constraints.

Short preview of how to do that:

yourConstraint.constant = newValue

UIView.animate(withDuration: animationDuration) {
yourView.layoutIfNeeded()
}

More information about this can be found here.



Related Topics



Leave a reply



Submit