0

I'm trying to make a view fall as a custom segue transition, but when the perform method is called in the UIStoryboardSegue implementation, it does not fall. I have tried moving the view to be dropped into the source's view to see if it does anything, but it doesn't.

-(void)perform {
    UIViewController *src  = (UIViewController *)self.sourceViewController;
    UIViewController *dest = (UIViewController *)self.destinationViewController;

    UIView *viewdrop = [dest.view snapshotViewAfterScreenUpdates:YES];
    viewdrop.frame = CGRectMake(0, -src.view.frame.size.height, dest.view.frame.size.width, dest.view.frame.size.height);
    [src.view addSubview:viewdrop];

    animator = [[UIDynamicAnimator alloc] initWithReferenceView:src.view];

    UIGravityBehavior* gravityBehavior = [[UIGravityBehavior alloc] initWithItems:@[viewdrop]];
    [animator addBehavior:gravityBehavior];
}
matt
  • 515,959
  • 87
  • 875
  • 1,141
Tillson
  • 530
  • 2
  • 14

1 Answers1

2

The reason it doesn't drop is because the gravity behavior takes time, but the segue itself is deallocated as soon as the perform method finishes. So, you need a way to keep the segue alive at least until the movement is complete. One way to do this is to make a strong property for the segue in the source view controller, and set its value in prepareForSegue,

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    self.dropSegue = segue;
}

I made a modified version of your segue that also adds a collision behavior, and sets the source view controller as the delegate of the collision behavior, so I can use the delegate method, collisionBehavior:endedContactForItem:withBoundaryIdentifier:, to set the dropSegue property to nil (after a slight delay) which causes the segue to be deallocated,

-(void)collisionBehavior:(UICollisionBehavior *)behavior endedContactForItem:(id<UIDynamicItem>)item withBoundaryIdentifier:(id<NSCopying>)identifier {
    NSLog(@"collision ended with %@", identifier);
    [self performSelector:@selector(setDropSegue:) withObject:nil afterDelay:1];
}

Here is my version of the gravity drop segue,

@interface RDSegue ()
@property (strong, nonatomic) UIDynamicAnimator *animator;
@end

@implementation RDSegue

-(id)initWithIdentifier:(NSString *)identifier source:(UIViewController *)source destination:(UIViewController *)destination {

    if (self = [super initWithIdentifier:identifier source:source destination:destination]) {
        UIViewController *src  = self.sourceViewController;
        UIViewController *dest = self.destinationViewController;
        self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:src.view];
        [src addChildViewController:dest];
        [dest didMoveToParentViewController:src];
        dest.view.frame = CGRectMake(0, -src.view.bounds.size.height, src.view.bounds.size.width, src.view.bounds.size.height);
        [src.view addSubview:dest.view];
    }
    return self;
}

-(void)perform {
    UIGravityBehavior* gravityBehavior = [[UIGravityBehavior alloc] initWithItems:@[[self.destinationViewController view]]];
    UICollisionBehavior *collide = [[UICollisionBehavior alloc] initWithItems:@[[self.destinationViewController view]]];
    CGPoint left = CGPointMake(self.animator.referenceView.bounds.origin.x, self.animator.referenceView.bounds.origin.y + self.animator.referenceView.bounds.size.height);
    CGPoint right = CGPointMake(self.animator.referenceView.bounds.origin.x + self.animator.referenceView.bounds.size.width, self.animator.referenceView.bounds.origin.y + self.animator.referenceView.bounds.size.height);
    [collide addBoundaryWithIdentifier:@"bottom" fromPoint:left toPoint:right];
    [collide setCollisionDelegate:self.sourceViewController];
    [self.animator addBehavior:gravityBehavior];
    [self.animator addBehavior:collide];
}

-(void)dealloc {
    NSLog(@"In dealloc");
}
rdelmar
  • 103,982
  • 12
  • 207
  • 218
  • I have this in the same app as a SpriteKit game - It seems that if I run the game after this segue executes, the gravity in the game is all messed up. Do you know why off the top of your head? – Tillson Apr 13 '14 at 23:33
  • 1
    @user3477144, no, that seems weird. I don't know why the segue would affect the game. Are you using the same animator for both? – rdelmar Apr 13 '14 at 23:37
  • It seems that putting adding any sort of dynamic behavior (even if you set it to nil right after creating it) screws up gravity. – Tillson Apr 14 '14 at 00:37
  • This looks like something i could need to... but how should this segue be used? :o I don't know how to combine my storyboard with this Segue... – regetskcob Jul 11 '14 at 17:15
  • @DanielBocksteger, you just make a segue, set its type to custom, and fill in the class name of the custom segue you create. – rdelmar Jul 11 '14 at 18:18
  • @rdelmar okay, got this. But... http://stackoverflow.com/questions/24712143/uikit-dynamics-pop-modal-view-controlelr – regetskcob Jul 12 '14 at 10:46