Reputation: 2105
I'm trying to create a view where some items fall along normal gravity vector and others fall along an opposite vector
self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self];
// Normal Gravity
self.gravityBehavior = [[UIGravityBehavior alloc] initWithItems:@[ ]];
self.gravityBehavior.gravityDirection = CGVectorMake(0, 1);
[self.animator addBehavior:self.gravityBehavior];
// Inverse Gravity
self.inverseGravityBehavior = [[UIGravityBehavior alloc] initWithItems:@[ ]];
self.inverseGravityBehavior.gravityDirection = CGVectorMake(0, -1);
[self.animator addBehavior:self.inverseGravityBehavior];
I would think then I could just add some items to one behavior and some to the other, but it appears that adding the second gravity behavior overrides the first?
[self.gravityBehavior addItem: ballA];
[self.inverseGravityBehavior addItem: ballB];
Is this true, and if so is there another way to achieve this effect?
Upvotes: 1
Views: 1078
Reputation: 1784
This behavior is definitely possible. However, it cannot be achieved with one animator using differing UIGravityBehavior
s.
One solution would be to use two UIDynamicAnimator
instances, each with its own UIGravityBehavior
instance. Below is an example of a view controller that has two tap gesture recognizers attached, one for single tap, and one for double. The single will add a view that reacts to normal gravity. The double tap adds a view that reacts to inverted gravity. Obviously the code would need to be tweaked to match your specific requirements.
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong) UIDynamicAnimator *animator;
@property (nonatomic, strong) UIDynamicAnimator *secondAnimator;
@property (nonatomic, strong) UIGravityBehavior *normalGravity;
@property (nonatomic, strong) UIGravityBehavior *inverseGravity;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
self.normalGravity = [[UIGravityBehavior alloc] init];
[self.animator addBehavior:self.normalGravity];
self.secondAnimator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
self.inverseGravity = [[UIGravityBehavior alloc] init];
[self.inverseGravity setAngle:self.normalGravity.angle magnitude:(-1.0 * self.normalGravity.magnitude)];
[self.secondAnimator addBehavior:self.inverseGravity];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)viewWasTapped:(id)sender {
UIView *v = [[UIView alloc] initWithFrame:CGRectMake(30, 10, 25, 25)];
v.backgroundColor = [UIColor redColor];
[self.view addSubview:v];
[self.normalGravity addItem:v];
}
- (IBAction)viewWasDoubleTapped:(id)sender {
UIView *v = [[UIView alloc] initWithFrame:CGRectMake(90, 400, 25, 25)];
v.backgroundColor = [UIColor greenColor];
[self.view addSubview:v];
[self.inverseGravity addItem:v];
}
@end
A second option would be to use a UIPushBehavior
to simulate inverted gravity. Below is a similarly set up view controller, but without the second animator and using the push behavior.
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong) UIDynamicAnimator *animator;
@property (nonatomic, strong) UIGravityBehavior *normalGravity;
@property (nonatomic, strong) UIPushBehavior *pushBehavior;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
self.normalGravity = [[UIGravityBehavior alloc] init];
[self.animator addBehavior:self.normalGravity];
self.pushBehavior = [[UIPushBehavior alloc] initWithItems:@[] mode:UIPushBehaviorModeContinuous];
[self.pushBehavior setAngle:self.normalGravity.angle magnitude:(-1.0 * self.normalGravity.magnitude)];
[self.animator addBehavior:self.pushBehavior];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)viewWasTapped:(id)sender {
UIView *v = [[UIView alloc] initWithFrame:CGRectMake(30, 10, 25, 25)];
v.backgroundColor = [UIColor redColor];
[self.view addSubview:v];
[self.normalGravity addItem:v];
}
- (IBAction)viewWasDoubleTapped:(id)sender {
UIView *v = [[UIView alloc] initWithFrame:CGRectMake(90, 400, 25, 25)];
v.backgroundColor = [UIColor greenColor];
[self.view addSubview:v];
[self.pushBehavior addItem:v];
}
@end
In all situations be sure you are managing which items are being impacted by the UIDynamicAnimator
and the various behaviors so that you are not constantly adding to them and bogging the simulation down.
Upvotes: 6