4

Recently I used UIDynamics to animate an image view into place. However, because its autolayout y-pos constraint was set to off-screen, when navigating away from the screen and then returning to it, my image view was being placed off-screen again. The animation took about 3 seconds, so after three seconds I just reset the constraint. That feels a little hacky.

So my question is this: what is the proper way to handle autolayout and UIDynamics at the same time?

jancakes
  • 456
  • 4
  • 10
  • Proper way to handle UIDynamics and AutoLayout? Keep them separate at all costs. You can add dynamics to a view and then INTERNALLY to that view lay it out with auto layout. But don't use them together. – Fogmeister Mar 20 '14 at 17:16

2 Answers2

5

This is not really a dynamics problem. Autolayout is incompatible with any view animation, or any manual setting of the frame: when layout comes along, it is the constraints that will be obeyed. It is up to you, if you move a view manually in any way, to update the constraints to match its new position/size/whatever.

Having said that: with UIKit Dynamics, when the animation ends, the animator will pause, and the animator's delegate is notified:

https://developer.apple.com/library/ios/documentation/uikit/reference/UIDynamicAnimatorDelegate_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/UIDynamicAnimatorDelegate/dynamicAnimatorDidPause:

So that is the moment to update the constraints.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • *"Autolayout is incompatible with any view animation"*...although, you can animate a view layout that does not incorporate `UIKitDynamics` by updating the autolayout constraints themselves. (Or am I doing something that will bite me later?) – Anthony C Mar 23 '14 at 23:19
  • @AnthonyC What you're doing is perfectly right. The problem is that it doesn't work in all situations. Even outside of UIKit Dynamics, the autolayout constraints on a view not match the aspects of that view that you want to animate. For example, applying a rotation transform to a constrained view is typically a disaster. See my little essay here: http://stackoverflow.com/a/14105757/341994 – matt Mar 24 '14 at 01:31
3

You have a nice solution provided by Geppy Parziale in this tutorial.

Basically you can create an object that conforms to UIDynamicItem:

@interface DynamicHub : NSObject <UIDynamicItem>
    @property(nonatomic, readonly) CGRect bounds;
    @property(nonatomic, readwrite) CGPoint center;
    @property(nonatomic, readwrite) CGAffineTransform transform;
@end

That needs to init the bounds or it will crash:

- (id)init {
    self = [super init];
    if (self) {
        _bounds = CGRectMake(0, 0, 100, 100);
    }
    return self;
}

And then you use UIDynamics on that object and use the intermediate values to update your constraints:

DynamicHub *dynamicHub = [[DynamicHub alloc] init];

UISnapBehavior *snapBehavior = [[UISnapBehavior alloc] initWithItem:dynamicHub
                                           snapToPoint:CGPointMake(50.0, 150.0)];
[snapBehavior setDamping:.1];

snapBehavior.action = ^{
     self.firstConstraint.constant = [dynamicHub center].y;
     self.secondConstraint.constant = [dynamicHub center].x;
};

[self.animator addBehavior:snapBehavior];
Tiago Almeida
  • 14,081
  • 3
  • 67
  • 82