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;
Related
I need a label to receive single tap touch, so I wrote the following code:
#import "ViewController.h"
#interface ViewController ()
{
UILabel* label;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
label=[[UILabel alloc]initWithframe:CGRectMake(15 30 350 300)];
label.backgroundColor=[UIColor greenColor];
label.userInteractionEnabled = YES;
UITapGestureRecognizer* tap=[[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(handleTapOnLabel:)];
[tap setNumberOfTapsRequired:1];
[label addGestureRecognizer:tap];
[self.view addSubview:label];
}
- (void)handleTapOnLabel:(UITapGestureRecognizer *)tapGesture
{
NSLog(#"receive tap.");
}
Unluckly,the tapGesture cannot be recognized. Could any one help me with this strange issue? Thank you so much.
A label's user interaction is disabled by default:
label.userInteractionEnabled = YES
Once user double taps on image/screen, it adds an annotation on the screen. When it adds annotation image, I want also open a subview to add annotation detail. However, my subview does not come up.
Here is my code snippet.
#synthesize iViewController;
- (void)viewDidLoad {
[super viewDidLoad];
// adding gesture recognizer
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTapGesture:)];
tapGesture.numberOfTapsRequired = 2;
[self.imvPhoto addGestureRecognizer:tapGesture];
tapGesture.delegate = self;
}
- (void)handleTapGesture:(UITapGestureRecognizer *)sender {
if (sender.state == UIGestureRecognizerStateRecognized) {
// Here is the code for subview adding
iViewController = [[InventoryViewController alloc] init];
[self.view addSubview:iViewController.view];
iViewController.view.frame = CGRectMake(100, 100, 320, 460);
}
}
Based on #rdelmar feedback, here is the solution:
iViewController = (InventoryViewController *)[self.storyboardinstantiateViewControllerWithIdentifier:#"InventoryViewController"];
iViewController.view.frame = CGRectMake(728, 32, 300, 736);
[self.view addSubview:iViewController.view];
I have created image view through code like this -
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib
UIImageView *dot =[[UIImageView alloc] initWithFrame:CGRectMake(50,50,20,20)];
dot.image=[UIImage imageNamed:#"draw.png"];
[self.view addSubview:dot];
}
I want to add User Interaction to this UIImageView and then create a selector or action for this UIImageView when tapped how is this done?
It depends on what kind of action you want achieve. Generally speaking you'd be using UIGestureRecognizer. For instance if you want your image to respond to a tap gesture then you'd have something like the following.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib
dotArray = [NSMutableArray alloc]init];
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTapGesture:)];
for(int i = 0; i< 30; i++) {
UIImageView *dot =[[UIImageView alloc] ...
dot.image=[UIImage imageNamed:#"draw.png"];
dot.tag = i; //identify dot image.
[self.view addSubview:dot];
[dotArray addObject:dot];
[dot addGestureRecognizer:tapGesture];
...
}
[tapGesture release];
}
Then the methods to handle tap gesture...
-(void)handleTapGesture:(id)sender {
UITapGestureRecognizer * tapGesture = (UITapGestureRecognizer*)sender;
for(int i = 0; i<[dotArray count]; i++) {
UIImageView * dot = (UIImageView*)[dotArray objectAtIndex:i];
if(dot.tag == [tapGesture view].tag) {
//fade out animation
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5f];
dot.alpha = 0.0f;
[UIView commitAnimations];
}
For this to work, you need to make an array of dots and declare it as instance variable, otherwise the method can't access the dot.
Try like this:-
UIImageView *dot =[[UIImageView alloc] initWithFrame:CGRectMake(50,50,20,20)];
dot.image=[UIImage imageNamed:#"draw.png"];
[self.view addSubview:dot];
1) To implement the number of touch required is 1 refer this:-
UITapGestureRecognizer *doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(scrollViewDoubleTapped:)];
doubleTapRecognizer.numberOfTapsRequired = 2;
doubleTapRecognizer.numberOfTouchesRequired = 1;
[dot addGestureRecognizer:doubleTapRecognizer];
- (void)doubleTapped:(UITapGestureRecognizer*)recognizer
{
}
2) To implement the number of touch required is 2 refer this:-
UITapGestureRecognizer *twoFingerTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(scrollViewTwoFingerTapped:)];
twoFingerTapRecognizer.numberOfTapsRequired = 1;
twoFingerTapRecognizer.numberOfTouchesRequired = 2;
[dot addGestureRecognizer:twoFingerTapRecognizer];
- (void)twoFingerTapped:(UITapGestureRecognizer*)recognizer
{
}
Thank you all of you that helped me I put everyones answers together and got this as my final code.
//
// ViewController.m
// InvaderRush
//
// Created by Ajay Venkat on 13/12/2014.
// Copyright (c) 2014 AJTech. All rights reserved.
//
#import "ViewController.h"
#interface ViewController ()
{
NSArray *dotArray;
}
#end
#implementation ViewController
- (void)viewDidLoad {
UIImageView *dot =[[UIImageView alloc] initWithFrame:CGRectMake(50,50,100,100)];
dot.image=[UIImage imageNamed:#"invader.jpg"];
[self.view addSubview:dot];
dot.tag = 1; //identify dot image.
UITapGestureRecognizer *doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(doubleTapped:)];
doubleTapRecognizer.numberOfTouchesRequired = 1;
[dot addGestureRecognizer:doubleTapRecognizer];
dot.userInteractionEnabled = YES;
NSMutableArray *images =[[NSMutableArray alloc] initWithObjects: dot,nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)doubleTapped:(id)sender {
UIGestureRecognizer *recognizer = (UIGestureRecognizer*)sender;
UIImageView *imageView = (UIImageView *)recognizer.view;
if(imageView.tag==1) {
[imageView setImage:[UIImage imageNamed:#"space_invader.jpg"]];
}
}
-(void)handleTapGesture:(id)sender {
}
#end
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
I want to add click event in my custom header class.
Following is my code. When I click on Header area it gives EXC_BAD_ACCESS.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
UITapGestureRecognizer *singleFingerTap =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(handleSingleTap:)];
[self.view addGestureRecognizer:singleFingerTap];
}
return self;
}
- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer {
CGPoint location = [recognizer locationInView:[recognizer.view superview]];
//Do stuff here...
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//At View did load
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapDetected:)];
tapRecognizer.numberOfTapsRequired = 1;
[self.view addGestureRecognizer:tapRecognizer];
- (void)tapDetected:(UITapGestureRecognizer *)tapRecognizer
{
//addcodehere
}
If your custom header class is subclass of UIView means then use self instead of self.view
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
tapRecognizer.numberOfTapsRequired = 1;
[self.view addGestureRecognizer:tapRecognizer];
- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer {
CGPoint location = [recognizer locationInView:[recognizer.view superview]];
//Do stuff here...
}
May be this will helpful for you......
{
UITapGestureRecognizer *tapGestureRecognizer;
self.view.backgroundColor = [UIColor whiteColor];
/* Create the Tap Gesture Recognizer */
self.tapGestureRecognizer = [[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(handleTaps:)];
self.tapGestureRecognizer.numberOfTouchesRequired = 2;
self.tapGestureRecognizer.numberOfTapsRequired = 3;
[self.view addGestureRecognizer:self.tapGestureRecognizer];
}
- (void) handleTaps:(UITapGestureRecognizer*)paramSender
{
NSUInteger touchCounter = 0; for (touchCounter = 0;
touchCounter < paramSender.numberOfTouchesRequired;
touchCounter++)
{
CGPoint touchPoint =
[paramSender locationOfTouch:touchCounter inView:paramSender.view];
NSLog(#"Touch #%lu: %#",(unsigned long)touchCounter+1, NSStringFromCGPoint(touchPoint));
}
}
Instead of doing in init method try to do in ViewDidLoad.
- (void)viewDidLoad
{
[super viewDidLoad];
UITapGestureRecognizer *singleFingerTap =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(handleSingleTap:)];
[self.view addGestureRecognizer:singleFingerTap];
// Do any additional setup after loading the view from its nib.
}
And include this method in class extension as,
- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer ;
Or write it before viewDidLoad.