I'm attempting to implement a tap-gesture recognizer on a UIImageView. However I can't get the method that handles the tap event to fire. I've compared my code against the answers to many similar questions on stackoverflow but still the problem persists. Below is the relevant code from my application. Can someone show me what I've done wrong?
ViewController.h
IBOutlet UIImageView *topLeftImage;
-(IBAction)handleSingleTap:(UITapGestureRecognizer*)gestureView;
ViewController.m
- (void)viewDidUnload
{
[super viewDidUnload];
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
topLeftImage.userInteractionEnabled = YES;
[topLeftImage addGestureRecognizer:singleTap];
}
- (void)handleSingleTap:(UITapGestureRecognizer *)gestureRecognizer {
NSLog(#"Tap detected. Booyah!");
}
Try this instead. You put your code in viewDidUnload, completely the wrong place. You want viewDidLoad.
- (void)viewDidLoad
{
[super viewDidLoad];
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
topLeftImage.userInteractionEnabled = YES;
[topLeftImage addGestureRecognizer:singleTap];
}
Related
I try to call a method after a delay when the user start to dragging a scrollView.
This block below is called but the action define in this performselector: is called only when I stop to drag the scrollView
- (void)viewDidLoad {
[super viewDidLoad];
UIScrollView *sv = [[UIScrollView alloc] initWithFrame:self.view.frame];
sv.delegate = self;
sv.backgroundColor = [UIColor redColor];
[sv setContentSize:CGSizeMake(1000, 200)];
[self.view addSubview:sv];
}
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
NSLog(#"hey");
[self performSelector:#selector(myAction) withObject:nil afterDelay:3];
}
- (void)myAction
{
NSLog(#"Called 3secondes after begin dragging");
}
I also try with a NSTimer and in the background thread but the problem is the same...
Any Idea?
If you want to have the callback fired while you're still dragging, you must schedule it for Common Run Loop modes, like so:
[self performSelector:#selector(myAction) withObject:nil afterDelay:3 inModes:#[NSRunLoopCommonModes]];
That'll do the trick :)
I have an application with UIScrollView added as a subview of UIView. i have added UITextField,UITextview as a subView of UIScrollView .I want to dismiss the keyboard when i tap in the scroll view. how can i do this?
Just add UITapGestureRecognizer
- (void)viewDidLoad
{
[super viewDidLoad];
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTapGestureCaptured:)];
[scr addGestureRecognizer:singleTap];
}
- (void)singleTapGestureCaptured:(UITapGestureRecognizer *)gesture
{
//Get touch point
CGPoint touchPoint=[gesture locationInView:scr];
//Hide keyBoard
[self.view endEditing:YES];
}
In iOS 7, you can achieve this easily.
scrollView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;
Try this,
- (void)viewDidLoad
{
[super viewDidLoad];
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(dismissKeyboard)];
tapGesture.cancelsTouchesInView = NO;
[scrollView addGestureRecognizer:tapGesture];
[tapGesture release];
}
-(void)dismissKeyboard
{
[txtNotes resignFirstResponder];
[textView resignFirstResponder];
}
When I added the gesture to a subclass of UIScrollView, I was having problems with the various gestures in my view tree interfering with each other, such as being able to click on subviews, scroll the view, and have the keyboard dismiss in all cases. I came up with this solution, which can be setup from a superclass of UIScrollView or from a UIViewController.
The DismissKeyboardTapGesture class uses ARC, works with any text fields under the view, and doesn't take over any clicks from subviews like buttons. Also takes advantage of iOS7 scrolling effect to dismiss keyboard.
Setting up from UISScrollView superclass:
_dismissKeyboard = [[DismissKeyboardTapGesture alloc] initWithView:self];
or from UIViewController:
_dismissKeyboard = [[DismissKeyboardTapGesture alloc] initWithView:self.view];
Here is the class:
#interface DismissKeyboardTapGesture : NSObject <UIGestureRecognizerDelegate>
#end
#implementation DismissKeyboardTapGesture
- (id)initWithView:(UIView *)view
{
self = [super init];
if (self) {
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTap:)];
singleTap.cancelsTouchesInView = NO;
singleTap.delegate = self;
[view addGestureRecognizer:singleTap];
if ([view respondsToSelector:#selector(setKeyboardDismissMode:)]) {
// Bonus effect to dismiss keyboard by scrolling
((UIScrollView *)view).keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;
}
}
return self;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
// Don't stop any existing gestures in our view from working
if (otherGestureRecognizer.view == gestureRecognizer.view) {
return YES;
}
return NO;
}
- (void)singleTap:(UIGestureRecognizer*)gestureRecognizer
{
// Close keyboard for any text edit views that are children of the main view
[gestureRecognizer.view endEditing:YES];
}
#end
I want to package some UIViews suchs as UIButton, UIImageView in a single UIView.
When I try to display that view, it is not showing up on my RootViewController:
Here is the code of my UIView subclass :
#import "Hover.h"
#implementation Hover
- (id)init{
self = [super init];
if (self) {
// Initialization code
UIImage *hover = [UIImage imageNamed:#"Hover.png"];
UIImageView *imageView = [[UIImageView alloc] init];
imageView.image = hover;
imageView.frame = CGRectMake(0, 0, hover.size.width, hover.size.height);
imageView.alpha = 0.75;
[self addSubview:imageView];
[imageView release];
}
return self;
}
And here is the RootViewController class:
- (void)viewDidLoad
{
Hover *hover = [[Hover alloc] init];
[self.navigationController.view addSubview:hover];
[hover release];
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
The "hover view" is not displayed! However, when I add a single UIImageView to my RootViewController, it works!
In order for your view to display, you should override the -(id)initWithFrame:(CGRect)frame;, instead of writing a custom initializer.
Try this way :
-(id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if(self) {
// do init here...
}
return self;
}
Also, in the -(void)viewDidLoad; method, first send [super viewDidLoad];, and then alloc/init the view.
- (void)viewDidLoad
{
[super viewDidLoad];
Hover *hover = [[Hover alloc] init];
[self.navigationController.visibleViewController.view addSubview:hover];
[hover release];
// Do any additional setup after loading the view, typically from a nib.
}
Just a quick guess at a glance: If you're using a navigationcontroller, you should initWithRootViewController. You can't add a view to a navigationcontroller directly, Use push instead.
HTH
Marcus
So, another EXC_BAD_ACCESS topic on StackOverflow, but as I'm new to Objective-C this is still a topic I don't really grasp yet. Even though I have done a lot of research about it already.
The issue is the following. I have a UIScrollView that I have overwritten using a Custom Class (named MultiSelectView). If the user taps this UIScrollView and then I want to open a view that allows him to select some data.
So I have declared a UITapGestureRecognizer that calls the openMultiSelect: method. But on the line [parent.navigationController pushViewController:view animated:YES]; I get a Program received signal: "EXC_BAD_ACCESS". error. Why o why?
- (id) initWithCoder:(NSCoder *) coder {
self = [super initWithCoder: coder];
if (self) {
// Add a Tap Gesture Recognizer to the Scrollview.
// If the user taps the view, it triggers the 'openMultiSelect' method.
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(openMultiSelect:)];
[singleTap setNumberOfTapsRequired:1];
[singleTap setNumberOfTouchesRequired:1];
[self addGestureRecognizer:singleTap];
}
return self;
}
- (void)openMultiSelect:(UIGestureRecognizer *)gesture {
//int myViewTag = gesture.view.tag; // now you know which view called
DataSelectView *view = [[DataSelectView alloc] initWithNibName:#"DataSelectView" bundle:[NSBundle mainBundle]];
view.allowMultiSelect = YES;
[parent.navigationController pushViewController:view animated:YES];
[view release];
}
So the parent that you see is a ViewController that contains the tab. Is there a better way to do this? Because for now I have thus a ViewController that contains Tabs. In its activateTab: method I thus create the tab and pass self along. I do the same in the viewDidLoad for that tab to pass the parent to the custom UIScrollView:
- (void) activateTab:(int)index {
... code ...
self.tab_Basic = [[TabBasic alloc] initWithNibName:#"TabBasic" bundle: [NSBundle mainBundle]];
self.tab_Basic.parent = self;
... code ...
}
You should make some change to your callback method. Something like that:
- (void)openMultiSelect:(UIGestureRecognizer *)gesture {
//int myViewTag = gesture.view.tag; // now you know which view called
if(gesture.state == UIGestureRecognizerStateEnded){
DataSelectView *view = [[DataSelectView alloc] initWithNibName:#"DataSelectView" bundle:[NSBundle mainBundle]];
view.allowMultiSelect = YES;
[parent.navigationController pushViewController:view animated:YES];
[view release];
}
}
What you are doing wrong is releasing the object "view" too early, don't release it until the view is popped. That should fix the problem.
- (void)openMultiSelect:(UIGestureRecognizer *)gesture {
//int myViewTag = gesture.view.tag; // now you know which view called
DataSelectView *view = [[DataSelectView alloc] initWithNibName:#"DataSelectView" bundle:[NSBundle mainBundle]];
view.allowMultiSelect = YES;
[parent.navigationController pushViewController:view animated:YES];
Hey, I want to be able to check if user touches my UIView so I can dismiss my picker how can I do it actually? Thanks!
Try adding a UITapGestureRecognizer to your UIView class in the viewDidLoad of the UIViewController subclass that contains your UIView. It would look something like this:
- (void)viewDidLoad {
[super viewDidLoad];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(viewTapped:)];
tap.numberOfTapsRequired = 1;
[self.aView addGestureRecognizer:tap];
[tap release];
}
Then implement a handler for the tap which, based on the above code, would look like this:
-(void)viewTapped:(UITapGestureRecognizer *)recognizer {
//Add in your picker dismissal code here
}
Hope this helps,
Justin