Collision not working between items

2019-08-11 13:26发布

问题:

I'm using UIDynamics in my app. my app has two squares. one is fixed and the other can be moved (by applying a pan gesture). when i try to collide them they don't collide. the delegate methods never get called. here's my code and i hope someone can point out the problem.

    UIDynamicAnimator* animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
  UICollisionBehavior* collisionBehavior = [[UICollisionBehavior alloc] initWithItems:@[self.square1, self.square2]];
    collisionBehavior.translatesReferenceBoundsIntoBoundary = YES;

    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
    [self.square1 addGestureRecognizer:pan];
    [collisionBehavior setCollisionMode:UICollisionBehaviorModeEverything];
    [animator addBehavior:collisionBehavior];
    collisionBehavior.collisionDelegate = self;

回答1:

  1. Make animator as a property or instance variable. otherwise it will be cleared after view load.
  2. Make sure implemented UICollisionBehaviorDelegate protol and correspond methods

Here is my works implementation based on your code.

Interface:

#import <UIKit/UIKit.h>

@interface DynamicViewController : UIViewController<UICollisionBehaviorDelegate>

@property (strong, nonatomic) UIDynamicAnimator *animator;

@property (strong, nonatomic) UIPushBehavior *pushBehavior;

@end

Implementation:

@synthesize pushBehavior = _pushBehavior;
@synthesize animator = _animator;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    UIView *square1 = [[UIView alloc] initWithFrame:CGRectMake(100, 30, 30, 30)];
    square1.center = CGPointMake(150, 150);
    square1.backgroundColor = [UIColor greenColor];
    UIView *square2 = [[UIView alloc] initWithFrame:CGRectMake(100, 300, 30, 30)];
    square2.center = CGPointMake(250, 350);
    square2.backgroundColor = [UIColor redColor];
    [self.view addSubview:square1];
    [self.view addSubview:square2];

    _animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];

    UICollisionBehavior* collisionBehavior = [[UICollisionBehavior alloc] initWithItems:@[square1, square2]];
    collisionBehavior.translatesReferenceBoundsIntoBoundary = YES;
    [collisionBehavior setCollisionMode:UICollisionBehaviorModeEverything];
    collisionBehavior.collisionDelegate = self;
    [_animator addBehavior:collisionBehavior];

    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
    [square1 addGestureRecognizer:pan];
}

#pragma mark push behavior
- (void)handlePan:(UIPanGestureRecognizer *)gesture
{
    if(gesture.state == UIGestureRecognizerStateBegan){
        if (_pushBehavior) {
            [_animator removeBehavior:_pushBehavior];
        }
        _pushBehavior = [[UIPushBehavior alloc] initWithItems:@[gesture.view] mode:UIPushBehaviorModeContinuous];
        [_animator addBehavior:_pushBehavior];
    }

    CGPoint offset =[gesture translationInView:self.view];
    _pushBehavior.pushDirection = CGVectorMake(offset.x,offset.y);
    _pushBehavior.magnitude = sqrtf(offset.x * offset.x + offset.y * offset.y) / 50;
    if (gesture.state == UIGestureRecognizerStateEnded) {
        [_animator removeBehavior:_pushBehavior];
        _pushBehavior = nil;
    }
}

#pragma mark Colision delegate
- (void)collisionBehavior:(UICollisionBehavior*)behavior beganContactForItem:(id <UIDynamicItem>)item1 withItem:(id <UIDynamicItem>)item2 atPoint:(CGPoint)p;
{
    NSLog(@"Colision Began");
}
- (void)collisionBehavior:(UICollisionBehavior*)behavior endedContactForItem:(id <UIDynamicItem>)item1 withItem:(id <UIDynamicItem>)item2;
{
  NSLog(@"Colision End");
}


回答2:

Your UIDynamicAnimator* animator is destroyed when function ends due to ARC. Thats why you are not able to see any animations. Make it a instance variable and you will be fine.



回答3:

I think there is some bug with UIDynamics (but not 100% sure let me know if I'm wrong). I couldn't make my dynamic works until I created instance variables for UIDynamicAnimator and UIGravityBehavior. Try add instance variable to the .m file in class extension as:

UIDynamicAnimator* animator;
UICollisionBehavior* collisionBehavior;

And change your first two line of code to:

animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
collisionBehavior = [[UICollisionBehavior alloc] initWithItems:@[self.square1, self.square2]];

It should help.



回答4:

You have to specify the bounds using "addBoundaryWithIdentifier" for the collision class and remove the non-moving item form the collision