Collision not working between items - ios

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;

Make animator as a property or instance variable. otherwise it will
be cleared after view load.
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");
}

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.

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.

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

Related

How to fix error on handling PanGestureRecognizer when called from another class?

I want to add PanGestureRecognizer to UIView of UIViewController. I'm dividing view on nine equal parts and create an UIViews by them. Also I added PanGestureRocgnizer on every part. When I call it in another class where I need it it works fine but when I touch on the screen in some part to start handle method for PangestureRecognizer I get the Error: [UIView handlePanGestureRocognizer:]: unrecognized selector sent to instance 0x17de2ee0. This is my code:
#import "CustomGestureRecognizer.h"
#implementation CustomGestureRecognizer
#synthesize arrayOfPatternsForComparison;
#synthesize arrayOfSubviews;
#synthesize arrayOfPanGestureRecognizers;
- (void)initialize:(UIView *)view {
arrayOfPatternsForComparison = [[NSMutableArray alloc] init];
arrayOfSubviews = [[NSMutableArray alloc] init];
arrayOfPanGestureRecognizers = [[NSMutableArray alloc] init];
[self createPatternsForComparison];
[self splitScreenInParts:view];
[self setPanGestrueRecognizersOnEveryPartOfTheScreen];
}
- (void)createPatternsForComparison {
}
- (void)splitScreenInParts:(UIView *)view {
CGSize onePart = CGSizeMake(view.frame.size.width/3, view.frame.size.height/3);
CGFloat x_positionOfPart = 0;
CGFloat y_positionOfPart = 0;
for (NSUInteger j=0; j<3; j++) {
for (NSUInteger i=0; i<3; i++) {
UIView *_view = [[UIView alloc] initWithFrame:CGRectMake(x_positionOfPart, y_positionOfPart, onePart.width, onePart.height)];
[[_view layer] setBorderWidth:1.0];
[[_view layer] setBorderColor:[UIColor redColor].CGColor];
x_positionOfPart += onePart.width;
[arrayOfSubviews addObject:_view];
[view addSubview:_view];
}
y_positionOfPart += onePart.height;
x_positionOfPart = 0;
}
}
- (void)setPanGestrueRecognizersOnEveryPartOfTheScreen {
for (UIView *view in arrayOfSubviews) {
UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:view action:#selector(handlePanGestureRocognizer:)];
[[panGestureRecognizer view] setTag:[arrayOfSubviews indexOfObject:view]];
[view addGestureRecognizer:panGestureRecognizer];
}
}
- (void)handlePanGestureRocognizer:(UIPanGestureRecognizer *)sender {
NSLog(#"%d", [[sender view] tag]);
}
#end
and in another class of UIViewController I called it like this:
- (void)viewWillAppear:(BOOL)animated {
CustomGestureRecognizer *cgr = [[CustomGestureRecognizer alloc] init];
[cgr initialize:[self view]];
}
How to fix this? Thanks for your answers.
Because cgr is released when you call it.
You have to create a var CustomGestureRecognizer *cgr in .h and then:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
cgr = [[CustomGestureRecognizer alloc] init];
[cgr initialize:[self view]];
}
And then change this line
UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:view action:#selector(handlePanGestureRocognizer:)];
to
UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePanGestureRocognizer:)];
The problem is with this line.
UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:view action:#selector(handlePanGestureRocognizer:)];
Here you are passing the target as "view" which is here a subview. The target should be a viewController object like "self" or any other viewController object.
And also here you are just creating 9 views (I think in NSObject subclass) and adding to an array, but those are not added to any view as sub views. For this you can return that array to your viewController, and there add pan gesture to those views with self as target. Then it'll work.
I solved it by adding var *CustomGestureRecognizer cgr in .h of another class like anhtu said and change
UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:view action:#selector(handlePanGestureRocognizer:)];
target to self like Dev said.

Is it possible to add multiple UIGravityBehaviors to a UIDynamicAnimator?

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?
This behavior is definitely possible. However, it cannot be achieved with one animator using differing UIGravityBehaviors.
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.

Using UIKit's UIScrollView with SpriteKit

I read two questions here about that, both with the same answer. The suggested solution was to create the UIScrollView object, and then add it to the parent view of the SKScene in the target scene's didMoveToView:, removing it in willMoveFromView:.
And that is the target scene code I implemented:
#interface MQSSMakerScene ()
#property BOOL contentCreated;
#property MQSSMakerWorkspaceLayer *workspaceLayer;
#property MQSSMakerDockLayer *dockLayer;
#property UIScrollView *scrollView;
#end
#implementation MQSSMakerScene
- (id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size]) {
CGSize layerSize = CGSizeMake(944, 140);
CGPoint layerPosition = CGPointMake(40, 768-(140+30));
CGRect viewFrame = CGRectMake(layerPosition.x, layerPosition.y, layerSize.width, layerSize.height);
_scrollView = [[UIScrollView alloc] initWithFrame:viewFrame];
_scrollView.contentSize = CGSizeMake(2000, 120);
_scrollView.scrollEnabled = YES;
_scrollView.showsHorizontalScrollIndicator = YES;
_scrollView.backgroundColor = [UIColor brownColor];
}
return self;
}
- (void)didMoveToView:(SKView *)view
{
[super didMoveToView:view];
if(!self.contentCreated) {
[self createSceneContents];
self.contentCreated = YES;
}
[self.view addSubview:_scrollView]; // --> WHERE IT'S BEING ADDED
}
- (void)willMoveFromView:(SKView *)view
{
[super willMoveFromView:view];
[_scrollView removeFromSuperview]; // --> WHERE IT'S BEING REMOVED
}
- (void)createSceneContents
{
self.backgroundColor = [UIColor colorWithHue:.237 saturation:.56 brightness:.46 alpha:1];
self.scaleMode = SKSceneScaleModeAspectFill;
[self addChild:[self newMakerLayout]];
}
- (SKNode *)newMakerLayout
{
SKNode *mainLayout = [[SKNode alloc] init];
self.workspaceLayer = [[MQSSMakerWorkspaceLayer alloc] init];
self.dockLayer = [[MQSSMakerDockLayer alloc] init];
[mainLayout addChild:self.workspaceLayer];
[mainLayout addChild:self.dockLayer];
MQSSStoryObject *ob1 = [[MQSSStoryObject alloc] initWithImageNamed:#"maker-1.png"];
[self.workspaceLayer addChild:ob1];
return mainLayout;
}
#end
Please note that the user should go to this scene from the home scene when clicking on a button. The problem now is that once I add the line:
[self.view addSubview:_scrollView];
to add the UIScrollView object to this scene, the application no more goes to this scene and instead add the UIScrollView to the home scene I am transitioning from. It also doesn't remove it when transitioning to another scene. Once I comment out this line, everything works just as expected, clearly without presenting the UIScrollView.
I am stuck. Any help or advice is highly appreciated. Thanks!
I finally figured out what the problem was for me. I was using the -(void)willLayoutSubviews method of the viewController to ensure I had the correct bounds, but I had forgotten to see if my SKScene was already presented. That resulted in a new welcomeScene being presented each time the view was laid out on top of the old one.
-(void)willLayoutSubviews
{
if(!self.didPresentScene)
{
// Present scene here
....
self.didPresentScene = YES;
}
}

scale, rotate and move with UIGestureRecognizer simultaneously

I can't find out why my scale, rotate and move won't work at the same time..
I have looked at a lot of examples and i can't seem to find the problem.
firstly I thought that is was a gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer problem, but it wasn't please help :)
here is my code:
#implementation StoryEditorPageHolderView
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
return YES;
}
- (id)initWithProperty:(Property *)property scale:(CGFloat)scaleFactor pos:(CGPoint)point dustbin:(DustbinView *)dustBin{
self = [super initWithFrame:CGRectZero];
if(self){
self.imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:property.imageName]];
self.frame = CGRectMake(0, 0, self.imageView.frame.size.width, self.imageView.frame.size.height);
[self addSubview:_imageView];
UIPinchGestureRecognizer *pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(scale:)];
[self addGestureRecognizer:pinchRecognizer];
UIRotationGestureRecognizer *rotationRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(rotate:)];
[self addGestureRecognizer:rotationRecognizer];
UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(move:)];
[panRecognizer setMinimumNumberOfTouches:1];
[panRecognizer setMaximumNumberOfTouches:1];
[self addGestureRecognizer:panRecognizer];
UITapGestureRecognizer *tapProfileImageRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapped:)];
[tapProfileImageRecognizer setNumberOfTapsRequired:2];
[self addGestureRecognizer:tapProfileImageRecognizer];
}
return self;
}
- (void)rotate:(UIRotationGestureRecognizer *)rotate {
if (rotate.state == UIGestureRecognizerStateBegan) {
prevRotation = 0.0;
}
float thisRotate = rotate.rotation - prevRotation;
prevRotation = rotate.rotation;
self.transform = CGAffineTransformRotate(self.transform, thisRotate);
}
- (void)scale:(UIPinchGestureRecognizer *)pinch {
if (pinch.state == UIGestureRecognizerStateBegan)
prevPinchScale = 1.0;
float thisScale = 1 + (pinch.scale-prevPinchScale);
prevPinchScale = pinch.scale;
self.transform = CGAffineTransformScale(self.transform, thisScale, thisScale);
}
-(void)move:(UIPanGestureRecognizer *)pan {
if (pan.state == UIGestureRecognizerStateBegan){
prevPanPoint = [pan locationInView:self.superview];
}
CGPoint curr = [pan locationInView:self.superview];
float diffx = curr.x - prevPanPoint.x;
float diffy = curr.y - prevPanPoint.y;
CGPoint centre = self.center;
centre.x += diffx;
centre.y += diffy;
self.center = centre;
prevPanPoint = curr;
}
#end
I also have UIGestureRecognizerDelegate as a delegate in the .h file:
#import <Foundation/Foundation.h>
#class Property;
#class DustbinView;
#interface StoryEditorPropertyView : UIView <UIGestureRecognizerDelegate>
#property (strong, nonatomic) UIPanGestureRecognizer *panRecognizer;
#property (strong, nonatomic) UIPinchGestureRecognizer *pinchRecognizer;
#property (strong, nonatomic) UIRotationGestureRecognizer *rotationRecognizer;
#property (strong, nonatomic) UITapGestureRecognizer *tapProfileImageRecognizer;
#property (strong, nonatomic) UIImageView *imageView;
#property (strong, nonatomic) Property *property;
#property (nonatomic) CGPoint pointBegin;
#property (nonatomic) bool isRemoveable;
#property (nonatomic) CGFloat beginScale;
#property (strong, nonatomic) DustbinView *dustBin;
- (id)initWithProperty:(Property *)property scale:(CGFloat)scaleFactor pos:(CGPoint)point dustbin:(DustbinView *)dustBin;
#end
This worked for me:
UIPinchGestureRecognizer *pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(scale:)];
pinchRecognizer.delegate = self;
[self addGestureRecognizer:pinchRecognizer];
UIRotationGestureRecognizer *rotationRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(rotate:)];
pinchRecognizer.delegate = self;
[self addGestureRecognizer:rotationRecognizer];
UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(move:)];
pinchRecognizer.delegate = self;
[panRecognizer setMinimumNumberOfTouches:1];
[panRecognizer setMaximumNumberOfTouches:1];
[self addGestureRecognizer:panRecognizer];
ok, what you're doing wrong is not adding an object for the UIGestureRecognizer to adapt to. For example, you have the
UITapGestureRecognizer *tapProfileImageRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapped:)];
[tapProfileImageRecognizer setNumberOfTapsRequired:2];
[self addGestureRecognizer:tapProfileImageRecognizer];
This is exactly what you need except this line
[self addGestureRecognizer:tapProfileImageRecognizer];
this is adding the gesture onto the class. you need an OBJECT :)
so just do this
[self.view addGestureRecognizer:tapProfileImageRecognizer];
for all your gestures, and it should work :)
You always have to make sure you're adding onto the object, not the class
Hope this helps!!
EDIT:
Putting UIGestureRecognizers onto UIView is the way that you would do what you are doing. What you need to do now is go under Xcode,
file -> new file
make a UIViewController subclass
make sure that name it...
under your .xib file, find this:
Then, if you look at where the UIView is, click that. This will bring up the UIView attributes panel. Travel over to the little button that has the i in the circle. It's the blue one under the Attributes panel. Click that, and you should see this:
Where you see the box that says 'UIView'
That is where you type your subclass of UIView.
That should help with any of the issues you have been having. Hope that helps! :)
adding gesture code you should put in viewDidLoad not in init method and add gesture in view(self.view) not in object(self) itself .
try as follow I made some changes
-(void) viewDidLoad
{
UIPinchGestureRecognizer *pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(scale:)];
[self.view addGestureRecognizer:pinchRecognizer];
UIRotationGestureRecognizer *rotationRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(rotate:)];
[self.view addGestureRecognizer:rotationRecognizer];
UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(move:)];
[panRecognizer setMinimumNumberOfTouches:1];
[panRecognizer setMaximumNumberOfTouches:1];
[self.view addGestureRecognizer:panRecognizer];
UITapGestureRecognizer *tapProfileImageRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapped:)];
[tapProfileImageRecognizer setNumberOfTapsRequired:2];
[self.view addGestureRecognizer:tapProfileImageRecognizer];
}

UIGestureRecognizer not working

Not sure what i'm doing wrong but here's a simplified example:
#interface Test : NSObject<UIGestureRecognizerDelegate> {
UIView *_someParentView;
UIView *_someChildView;
}
- (id)initWithParentView:(UIView *)parentView;
#end
#implementation Test
- (id)initWithParentView:(UIView *)parentView
{
if (self = [super init])
{
_someParentView = parentView;
}
return self;
}
- (void)addSubViewsWhenReady
{
_someChildView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
_someChildView.backgroundColor = [UIColor blackColor];
[_someChildView setUserInteractionEnabled:YES];
[_someParentView addSubview:_someChildView];
UITapGestureRecognizer *singleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
singleFingerTap.delegate = self;
[_someChildView addGestureRecognizer:singleFingerTap];
}
- (void)handleSingleTap:(id)sender
{
NSLog(#"handle the single tap");
}
#end
The output: "handle the single tap" is never logged. Any ideas on what im doing wrong?
Thanks!
Setting the target like you are doing:
UITapGestureRecognizer *singleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
is your problem. If "self" here is a UIViewController, it will work.
i.e.
#interface Test : UIViewController<UIGestureRecognizerDelegate> {
UIView *_someParentView;
UIView *_someChildView;
}
- (id)initWithParentView:(UIView *)parentView;
#end
#implementation Test
- (id)initWithParentView:(UIView *)parentView
{
if (self = [super init])
{
_someParentView = parentView;
}
return self;
}
- (void)addSubViewsWhenReady
{
_someChildView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
_someChildView.backgroundColor = [UIColor blackColor];
[_someChildView setUserInteractionEnabled:YES];
[_someParentView addSubview:_someChildView];
UITapGestureRecognizer *singleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
singleFingerTap.delegate = self;
[_someChildView addGestureRecognizer:singleFingerTap];
}
- (void)handleSingleTap:(UIGestureRecognizer*)recognizer {
NSLog(#"handle the single tap");
}
#end
Try changing your definition of handleSingleTap: to
- (void)handleSingleTap:(UIGestureRecognizer*)recognizer {
NSLog(#"handle the single tap");
}
From the UIGestureRecognizer docs:
A gesture recognizer has one or more target-action pairs associated with it. If there are multiple target-action pairs, they are discrete, and not cumulative. Recognition of a gesture results in the dispatch of an action message to a target for each of those pairs. The action methods invoked must conform to one of the following signatures:
- (void)handleGesture;
- (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer;

Resources