iosobjective-cswiftuikituikit-dynamics

UIKit Dynamics change a view frame with collisions


My project has several views that are subject to radial gravity at the center of their parent view, and elastic collisions so that they don't overlap. It works great, but sometimes I need to resize the views, and, when a view gets larger, the other views must move away from it so that all the views remain non-overlapping. I would expect the collision behavior to realize things are touching and to move them apart, but it doesn't seem to.

Here's what I'm trying now:

[UIView animateWithDuration:0.5 animations:^{
    view.frame = CGRectInset(view.frame, -30, -30);
} completion:^(BOOL finished) {
    [self.animator updateItemUsingCurrentState:view];
}];

The view grows just fine, the animation delegate is informed that the animation has resumed, but the other views don't move away. The newly enlarged view just overlaps (or underlaps depending on z order) the other views.

I tried changing the transform and not the frame - no dice. I tried removing the view from all the behaviors - no dice. I tried removing some and all of the behaviors from the animator - no dice. I tried calling updateItemUsingCurrentState: on all of the views - no dice. I need some dice!

Can you help? Thanks...(swift-ies, feel free to answer is swift. I'll translate it)


Solution

  • Thanks to this post, I learned that all behaviors that include the item being changed must be removed from the animator, then, after changing the view's properties, the behaviors should be added back to the animator.

    I think that's crazy, but it worked.

    [self.animator removeBehavior:self.behavior]; // for all behaviors that have view as an item
    
    [UIView animateWithDuration:0.5 animations:^{
        view.frame = CGRectInset(view.frame, -30, -30);
    } completion:^(BOOL finished) {
        [self.animator updateItemUsingCurrentState:view];
        [self.animator removeBehavior:self.behavior];
    }];