I'm trying to setup a tap gesture in my code and I get a crash when I try to determine the coordinates. Any help would be appreciated.
2012-09-14 17:25:49.149 valhalla[16469:707] tap detected
2012-09-14 17:25:49.159 valhalla[16469:707] -[UITapGestureRecognizer translationInView:]: unrecognized selector sent to instance 0x37bf10
2012-09-14 17:25:49.165 valhalla[16469:707] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UITapGestureRecognizer translationInView:]: unrecognized selector sent to instance 0x37bf10'
*** First throw call stack:
(0x3104c88f 0x3611d259 0x3104fa9b 0x3104e915 0x3104f788 0x7a4a1 0x31870637 0x31800d65 0x31a31479 0x3177cf55 0x3177baa3 0x317887e9 0x31788627 0x317881f5 0x3176e695 0x3176df3b 0x313e222b 0x31020523 0x310204c5 0x3101f313 0x30fa24a5 0x30fa236d 0x313e1439 0x3179ccd5 0x75307 0x752c8)
#import "GLViewController.h"
#import "GLView.h"
#implementation GLViewController
- (void)loadView {
CGRect applicationFrame = [[UIScreen mainScreen] applicationFrame];
GLView *glView = [[[GLView alloc] initWithFrame:applicationFrame] autorelease];
self.view = glView;
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(handleSingleTap:)];
singleTap.numberOfTapsRequired = 1;
[self.view addGestureRecognizer:singleTap];
[singleTap release];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// We can run in landscape mode
return (UIInterfaceOrientationIsLandscape(interfaceOrientation));
}
/*- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
//[self.view becomeFirstResponder];
//[self.view setReturnKeyType:UIReturnKeyDone];
}*/
- (void)didReceiveMemoryWarning
{
// default behavior is to release the view if it doesn't have a superview.
// remember to clean up anything outside of this view's scope, such as
// data cached in the class instance and other global data.
[super didReceiveMemoryWarning];
}
- (void) handleSingleTap: (UIPanGestureRecognizer *) uigr
{
NSLog(#"tap detected");
CGPoint translation = [uigr translationInView:self.view];
CGPoint finalPosition = self.view.center;
finalPosition.x += translation.x;
finalPosition.y += translation.y;
}
#end
Your declaring a UITapGestureRecognizer but your method is casting to a UIPanGestureRecognizer
- (void) handleSingleTap: (UIPanGestureRecognizer *) uigr
UITapGestureRecognizer does not declare translationInView. That is why your app is crashing.
You want to be using locationInView: not translationInView:
Related
I have a View which is the subView of the main view in iphone app I want that when subView is shown and user taps on part of the screen except the subView then subView should hide.
Here is the code which I got but it does not hide it :
UITapGestureRecognizer *tapGR;
tapGR = [[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap:)] autorelease];
tapGR.numberOfTapsRequired = 1;
[self.View addGestureRecognizer:tapGR];
// Add a delegate method to handle the tap and do something with it.
-(void)handleTap:(UITapGestureRecognizer *)sender
{
if (sender.state == UIGestureRecognizerStateEnded) {
// handling code
[myViewSheet removeFromSuperView];
}
}
implement UIGestureRecognizerDelegate protocol:
.h:
#interface YourView : UIView<UIGestureRecognizerDelegate>
.m:
#implementation YourView{
UIView * subview;
}
...
subview = [[UIView alloc]initWithFrame:CGRectMake(0, 200, 320, 200)];
[self addSubview:subview];
UITapGestureRecognizer *tapGR;
tapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap:)];
tapGR.numberOfTapsRequired = 1;
tapGR.delegate = self;
[self addGestureRecognizer:tapGR];
...
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if (touch.view == subView)
{
return NO;
}
else
{
return YES;
}
}
You probably need to set userInteractionEnabled = YES on your main view (The one to which you are attaching the gesture recognizer.)
On parentClass(inheriting from UIView) i have:
[self addGestureRecognizer:_tapGesture]; // _tapGesture is UITapGestureRecognizer, with delegate on parentClass
On someClass:
[_myImageView addGestureRecognizer:_imageViewGestureRecognizer]; // _imageViewGestureRecognizer is UITapGestureRecognizer, with delegate on someClass
The problem is that when i tap on myImageView both gesture recognizers are firing. I want only _imageViewGestureRecognizer to work.
I've tried:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)recognizer shouldReceiveTouch:(UITouch *)touch {
UIView *gestureView = recognizer.view;
CGPoint point = [touch locationInView:gestureView];
UIView *touchedView = [gestureView hitTest:point withEvent:nil];
if ([touchedView isEqual:_imageViewGestureRecognizer]) {
return NO;
}
return YES;
}
But it ofc doesn't take upon consideration gesture recognizer from super class.
I did this little test and it worked perfectly...
#implementation View
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
self.backgroundColor = [UIColor whiteColor];
UITapGestureRecognizer* tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapped1)];
[self addGestureRecognizer:tap];
UIImageView* img = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"test.png"]];
img.userInteractionEnabled = YES;
img.frame = CGRectMake(0, 0, 100, 100);
[self addSubview:img];
UITapGestureRecognizer* tap2 = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapped2)];
[img addGestureRecognizer:tap2];
return self;
}
-(void)tapped1 {
NSLog(#"Tapped 1");
}
-(void)tapped2 {
NSLog(#"Tapped 2");
}
#end
What you wanted was iOS's default behaviour. Once a subview has taken care of a touch, its superview won't receive the touch anymore. Did you set userInteractionEnabled on the imageView?
Using xCode 4.3.2, I have the following code in initWithFrame in my view.m:
UIPinchGestureRecognizer *recognizer = [[UIPinchGestureRecognizer alloc]
initWithTarget: self action: #selector(pinch:)
];
oldScale = recognizer.scale;
[self pinch: recognizer];
[self addGestureRecognizer: recognizer];
// code to create label is also in here, works. label displays no problem
[self addSubview: label];
my pinch method is as follows:
- (void) pinch: (UIPinchGestureRecognizer *) recognizer
{
NSLog(#"pinch:");
label.bounds = CGRectMake(
(self.bounds.size.width - width * recognizer.scale) / 2,
(self.bounds.size.height - height * recognizer.scale) / 2,
width * recognizer.scale,
height * recognizer.scale
);
label.font = [UIFont systemFontOfSize: 20 * recognizer.scale];
NSString *verdict;
if (recognizer.scale > oldScale) {
verdict = #"spread";
} else if (recognizer.scale < oldScale) {
verdict = #"pinch";
} else {
verdict = #"neither";
}
oldScale = recognizer.scale;
label.text = [NSString stringWithFormat: #"%# %g",
verdict, recognizer.scale
];
}
because i actually call pinch in my initWithFrame method, it runs once, but when i perform a pinch in the iphone simulator, it doesn't register at all. is there some setting in xcode 4.3.2 i don't know about? this code works everywhere else i've tried running it - but those versions of xcode are all 4.3.
Add UIGestureRecognizerDelegate in .h file
Use following code in .m file in view did load...
// Gesture Reconizer Delegate Methods
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
return YES;
}
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
return YES;
}
UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:#selector(checkpinch)];
[pinch setDelegate:self];
[pinch setDelaysTouchesBegan:YES];
[self.ScrollView addGestureRecognizer:pinch];
[pinch release];
// Gesture Reconizer Methods
-(void)checkpinch {
NSLog(#"YES");
}
>>See this Edited..
Pinch can detect on scroll-view if you want to detect on view than see following reference...
Detect pinch on UIView
Hope, this will help you...
Maybe I am oversimplifying this, but wouldn't be easier to: 1) In your VC, create an IBoutlet property to an instance of your view 2) connect that IBOutlet to your view 3) setup your UIPinchGetsureRecognizer in the VC by overriding the view setter method and change target to the view and keep the pinch method in the view. This way the UIPinchGetsureRecognizer will load every time the view is loaded and be ready for a pinch. Then you would not need to call the pinch method (which defeats the purpose). KB
For a exercise I created a project to experiment with the accelerometer functions of the iPhone. Right now when I run the app on my device it begins with a blank screen, shake the phone and a image is displayed.
I have to force close the app to clear the image. I was hoping someone could provide a solution that would make the image reset so I could repeat the process as many times as I wanted. (shake phone, display image, clear image) I'm thinking it needs a timer or something, not sure. Here is the source code. Thanks for taking the time to read and help.
// ViewController.m
// AccelTest
//
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
-(void)viewWillAppear:(BOOL)animated{
[self startAccel];
[self view];
}
-(void)viewWillDisappear:(BOOL)animated{
[self stopAccel];
[self view];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return NO;
}
-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration{
double const kThreshold = 2.0;
// double const kThreshold = 2.0;
if ( fabsf(acceleration.x) > kThreshold
|| fabsf(acceleration.y) > kThreshold
|| fabsf(acceleration.z) > kThreshold){
[self.view addSubview:[[UIImageView alloc]initWithImage:[UIImage imageNamed:#"Icon.png"]]];
}
}
-(void)startAccel{
UIAccelerometer * accel = [UIAccelerometer sharedAccelerometer];
accel.delegate = self;
accel.updateInterval = .25;
}
-(void)stopAccel{
UIAccelerometer * accel = [UIAccelerometer sharedAccelerometer];
accel.delegate = nil;
}
#end
Here is how I would do it (without ARC) to tap the image to make it disappear.
Remove your line:
[self.view addSubview:[[UIImageView alloc]initWithImage:[UIImage imageNamed:#"Icon.png"]]];
And add these lines instead:
UIImageView *myImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Icon.png"]];
myImageView.userInteractionEnabled = YES;
UITapGestureRecognizer *tapgr = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(rm:)];
[myImageView addGestureRecognizer:tapgr];
[tapgr release]; tapgr = nil;
[self.view addSubview:myImageView];
[myImageView release]; myImageView = nil;
Then add a method to the View Controller to remove the UIImageView when it is tapped.
-(void)rm:(UITapGestureRecognizer *)tapgr {
[tapgr.view removeFromSuperview];
}
When that Image is tapped once, the rm: method will be called which will remove the Image from self.view
Store a pointer to that image view somewhere and remove it from it's superview when you want to. Either with a timer, or user action, or something like that.
I have a custom init method:
- (id) initWithFrame:(CGRect ) frame andImage:(UIImage *) image
{
self = [super init];
if (self){
self.view.frame = frame;
self.imageView_.image = image;
self.imageScrollView_.frame = self.view.frame;
imageOriginalFrame = frame;
zoomedImageFrame = frame;
NSLog(#"SCREEN DIM %f AND %f", zoomedImageFrame.size.height, zoomedImageFrame.origin.y);
}
return self;
}
and here's how I present it:
FullSizeImageViewController * fullSize = [[FullSizeImageViewController alloc] initWithFrame:imageOriginalFrame andImage:image];
if ([self.delegate respondsToSelector:#selector(fullStoryViewController:presentModalViewController:animated:)]) {
[self.delegate fullStoryViewController:self presentModalViewController:fullSize animated:YES];
}
However, surprisingly my viewDidLoad is getting called before the initWithFrame. How is this possible?
I am guessing it's because I call super init? If not how do I do this?
Your viewDidLoad method is not getting called before your initWithFrame:andImage: method. Your viewDidLoad method is getting called during your initWithFrame:andImage: method.
Your initWithFrame:andImage: method contains this line:
self.view.frame = frame;
which is shorthand for this:
[[self view] setFrame:frame];
So your method is calling the -[UIViewController view] method. The -[UIViewController view] method is basically this:
- (UIView *)view {
if (!_view) {
[self loadView];
[self viewDidLoad];
}
return _view;
}
Try putting a breakpoint in your viewDidLoad method. When it's hit, look at the stack trace. You'll find initWithFrame:andImage: in it.