Question

I'm trying to use UICollisionBehavior in UIKit Dynamics to figure out when a view that I've thrown off screen (using UIAttachmentBehavior and UIPushBehavior) is actually fully off screen.

I'm finding it complicated because I'm not able to track it as it progresses, once it's thrown I'm trying to figure out using UICollisionBehavior to detect when its last edge has "collided" with its superview. This seems to be the easiest way to figure out when it's off screen compared to an NSTimer solution or something similar (but if you can think of any easier way, I'm all ears!).

A solution I saw in this project (specifically here) was as follows:

CGRect referenceBounds = self.animator.referenceView.bounds;
CGFloat inset = -hypot(CGRectGetWidth(referenceBounds), CGRectGetHeight(referenceBounds));
UIEdgeInsets edgeInsets = UIEdgeInsetsMake(inset, inset, inset, inset);
[self.collisionBehavior setTranslatesReferenceBoundsIntoBoundaryWithInsets:edgeInsets];

Which calculates where the collision bounds are I'm guessing (to be honest I don't completely understand it) and then when the delegate gets called when the collision is detected I call removeFromSuperview.

But for whatever reason this works very unreliably. Sometimes I'll throw it off screen and it'll actually never call the collision detected delegate somehow. Often the timing will be a little late as well.

As far as my setup goes it's just throwing a UIScrollView off screen that has its frame set to the bounds of its superview (self.view in the view controller).

Is there a better way to setup collision detection for when it leaves the view?

Was it helpful?

Solution

In this answer I illustrate how to handle the dragging of a view off-screen with UIKit Dynamics. Specifically, rather than using UICollisionBehavior (or NSTimer or whatever), I'd suggest specifying an action block that checks for when the views no longer intersect. This illustrates the idea when using a UIDynamicItemBehavior, but the idea works with any UIKit dynamic behaviors:

UIDynamicItemBehavior *dynamic = [[UIDynamicItemBehavior alloc] initWithItems:@[viewToAnimate]];
[dynamic addLinearVelocity:velocity forItem:viewToAnimate];
[dynamic addAngularVelocity:angularVelocity forItem:viewToAnimate];

// when the view no longer intersects with its superview, go ahead and remove it

typeof(self) __weak weakSelf = self;
dynamic.action = ^{
    if (!CGRectIntersectsRect(gesture.view.superview.bounds, gesture.view.frame)) {
        [weakSelf.animator removeAllBehaviors];
        [viewToAnimate removeFromSuperview];
    }
};

// now add dynamic behavior

[self.animator addBehavior:dynamic];

Clearly, you should customize this to suit your particular scenario, but hopefully it illustrates the idea.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top