Why does my UITableView not respond to touchesBegan? - iphone

I am using this method
- (void)tableView:(UITableView *)tableView touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
if ([myPickerView isFirstResponder] && [touch view] != myPickerView) {
[myPickerView resignFirstResponder];
}
[super touchesBegan:touches withEvent:event];
}
but my tableView does not respond to touches (applied to the view works, but this is covered by the tableView!)
If this is not possible - is there any other possibility to capture "out of window" touches?

There is no such delegate method as tableView:touchesBegan:withEvent:. If you want to override -touchesBegan:withEvent: for your UITableView, you will need to subclass UITableView. Most problems like this are often better implemented with a UIGestureRecognizer. In the above, I'd probably use a UITapGestureRecognizer.

I found the simplest way to do this is to add a gesture recognizer to the UITableViewController's view.
I put this code in the UITableViewController's viewDidLoad:
UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap:)];
[self.view addGestureRecognizer:tap];
And implemented the event handler:
- (void)handleTap:(UITapGestureRecognizer *)recognizer
{
// your code goes here...
}
EDIT:
You could also add the gesture recognizer to the tableview, just change [self.view addGestureRecognizer:tap]; to [self.tableView addGestureRecognizer:tap];

Here is a UITableView subclass solution that worked for me. Make a subclass of UITableView and override hitTest:withEvent: as below:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
static UIEvent *e = nil;
if (e != nil && e == event) {
e = nil;
return [super hitTest:point withEvent:event];
}
e = event;
if (event.type == UIEventTypeTouches) {
NSSet *touches = [event touchesForView:self];
UITouch *touch = [touches anyObject];
if (touch.phase == UITouchPhaseBegan) {
NSLog(#"Touches began");
}
}
return [super hitTest:point withEvent:event];
}

Related

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {} is not working

I called the method,
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
[self.name resignFirstResponder];
[self.userName resignFirstResponder];
[self.mailId resignFirstResponder];
[self.password resignFirstResponder];
[self.reTypePassword resignFirstResponder];
}
for the purpose of resign first responder.it is working properly without using scrollview.but if i am using scrollview i cant able to use this method.why?
You can add a gesture recognizer if you need to use a scrollview.
Try this:
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(resignFirstResponder:)];
gestureRecognizer.delegate = self;
[scrollView addGestureRecognizer:gestureRecognizer];
-(void) resignFirstResponder:(UITapGestureRecognizer *) gesture
{
[self.name resignFirstResponder];
[self.userName resignFirstResponder];
[self.mailId resignFirstResponder];
[self.password resignFirstResponder];
[self.reTypePassword resignFirstResponder];
}
There are many more alternatives: See
UIScrollView prevents touchesBegan, touchesMoved, touchesEnded on view controller ,
UIScrollView touchesBegan

Cant get UIButton to highlight with TapGestureRecognizer

I've setup a tap gesture recognizer and add the recognizer to the uibutton. The button has a background image. When I tap the button it doesn't highlight at all, the only thing I've been able to get it to do is change it's alpha value.
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTapGestureCaptured:)];
singleTap.cancelsTouchesInView = NO;
[btnNext addGestureRecognizer:singleTap];
- (void)singleTapGestureCaptured:(UITapGestureRecognizer *)gesture
{
UIView *tappedView = [gesture.view hitTest:[gesture locationInView:gesture.view] withEvent:nil];
NSLog(#"Touch event view: %#",[tappedView class]);
UIButton *myButton = (UIButton *) tappedView;
[self highlightButton:myButton];
tappedView.alpha = 0.5f;
}
Any would be appreciated. Thanks
You can intercept the touches events with a gesture recognizer, and then programmatically add the recognizer to all your uibuttons. For instance:
//
// HighlighterGestureRecognizer.h
// Copyright 2011 PathwaySP. All rights reserved.
//
#import <Foundation/Foundation.h>
#interface HighlightGestureRecognizer : UIGestureRecognizer {
id *beganButton;
}
#property(nonatomic, assign) id *beganButton;
#end
and the implementation:
//
// HighlightGestureRecognizer.m
// Copyright 2011 PathwaySP. All rights reserved.
//
#import "HighlightGestureRecognizer.h"
#implementation HighlightGestureRecognizer
#synthesize beganButton;
-(id) init{
if (self = [super init])
{
self.cancelsTouchesInView = NO;
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
self.beganButton = [[[event allTouches] anyObject] view];
if ([beganButton isKindOfClass: [UIButton class]]) {
[beganButton setBackgroundImage:[UIImage imageNamed:#"grey_screen"] forState:UIControlStateNormal];
[self performSelector:#selector(resetImage) withObject:nil afterDelay:0.2];
}
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
}
- (void)reset
{
}
- (void)ignoreTouch:(UITouch *)touch forEvent:(UIEvent *)event
{
}
- (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer *)preventingGestureRecognizer
{
return NO;
}
- (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer
{
return NO;
}
- (void)resetImage
{
[beganButton setBackgroundImage: nil forState:UIControlStateNormal];
}
#end
The way you'd add the gesture recognizer to your button would be like so:
HighlighterGestureRecognizer * tapHighlighter = [[HighlighterGestureRecognizer alloc] init];
[myButton addGestureRecognizer:tapHighlighter];
[tapHighlighter release];
So basically you're declaring it, initializing it, and then adding it. After that, you'll want to release it, since the addGestureRecognizer retains it.
Also simply try
adjustsImageWhenHighlighted = YES set on your buttons? The default is YES, but maybe you changed it in the xib. It's the "Highlighted Adjusts Image" checkbox in the attributes inspector:

How can we able to make table view work when Gesture is applied to self.view?

I have applied gesture on whole view and I want to interact with table view within self.view.I have applied custom gesture.that is as follows:
#import "TouchEvent.h"
#import <UIKit/UIGestureRecognizerSubclass.h>
#implementation TouchEvent
#synthesize xInc=_inc;
#synthesize prev=_prev;
#synthesize diff=_diff;
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self setState:UIGestureRecognizerStateBegan];
}
-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[self setState:UIGestureRecognizerStateCancelled];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
// A tap can have slight movement, but we're not interested
// in a tap. We want more movement. So if a tap is detected
// fail the recognizer.
if ([self state] == UIGestureRecognizerStatePossible) {
[self setState:UIGestureRecognizerStateBegan];
} else {
[self setState:UIGestureRecognizerStateChanged];
}
UIView *view = [self view];
CGPoint touchpoint = [touch locationInView:view];
CGPoint prevPoint=[touch previousLocationInView:view];
if (prevPoint.x<touchpoint.x)
[self setDiff:(touchpoint.x-prevPoint.x)];
else
[self setDiff:(prevPoint.x-touchpoint.x)];
NSLog(#"difference is: %f",self.diff);
NSLog(#"x is: %f",touchpoint.x);
[self setXInc:touchpoint.x];
[self setPrev:prevPoint.x];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[self setState:UIGestureRecognizerStateEnded];
}
#end
and I m applying like this
- (void)viewDidLoad
{
NSArray *ary=[NSArray arrayWithObjects:#"Friends",#"Message",#"Chats",#"New Feeds",#"Photos",#"Notes", nil];
array=ary;
gestur=[[TouchEvent alloc] initWithTarget:self action:#selector(SLideTheView:)];
[self.view addGestureRecognizer:gestur];
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
-(void)moveIt:(CGFloat)x_pos
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelegate:self];
[viewU setFrame:CGRectMake(x_pos, 0, 320, 460)];
[UIView commitAnimations];
}
-(void)SLideTheView:(TouchEvent*)gesture
{
CGPoint pt=[gesture locationInView:viewU];
if (pt.x>13&&pt.y>5&&pt.x<29&&pt.y<23)
{
[self slideView];
}
else
{
if (gesture.state==UIGestureRecognizerStateEnded)
{
if (viewU.frame.origin.x!=0) {
if (gesture.prev<gesture.xInc)
{
[self moveIt:270];
}
else
[self moveIt:0];
}
}
else
{
if (viewU.frame.origin.x!=0)
{
if (gesture.prev<gesture.xInc)
x=viewU.frame.origin.x+gesture.diff;
else
x=viewU.frame.origin.x-gesture.diff;
[viewU setFrame:CGRectMake(x, 0, 320, 460)];
}
}
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
label.text=[array objectAtIndex:[indexPath row]];
[self slideView];
}
the running image is as follows:
you can use requireGestureRecognizerToFail: to able to recognize two or more gesture recognizers on same view see example code here
edit
so you can refer this one
the method to be referenced is - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
refer this question for more
//add gesture to mapview-for single touch
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(SLideTheView:)];
[self.view addGestureRecognizer:tap];
tap.numberOfTapsRequired = 1;
//add another gesture to terminate first one
UITapGestureRecognizer *secondGest= [[UITapGestureRecognizer alloc] init];
[tableview addGestureRecognizer:secondGest];
[tap requireGestureRecognizerToFail:secondGest];
[secondGest release];
[tap release];

How can I get touchesBegan event on SuperView

In my program there is two views(scrollView-super, view-sub*2).
In my case two subviews are subviewed in scrollView. touchesBegan event called in subviews.
How Can I get event in scrollView???
#interface MyScrollView:UIScrollView
...
#implement MyScrollView
...
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//here is my code
//but I can't get event here
...
}
-(id)initWithFrame:(CGRect) frame
{
...
MyView *view1 = [[MyView alloc] initWithFrame:(0, 0, 320, 240);
MyView *view2 = [[Myview alloc] initWithFrame:(0, 240, 320,240);
[self addSubview: view1];
[self addSibvoew: view2];
...
}
#interface MyView:UIView
...
#implement MyScrollView
...
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//break points
//here comes event
}
Try this code..
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTapGestureCaptured:)];
[scroll addGestureRecognizer:singleTap];
- (void)singleTapGestureCaptured:(UITapGestureRecognizer *)touch{
CGPoint touchPoint=[gesture locationInView:scrollView];
touchPoint = [touch locationInView:self.view];
}
I suggest making ur two subview global and then in the superview touchesbegan method pass the touches and the event to the subviews for handling. So somethig like [view1 touchesBegan:touches event:event];
i have not tested it but that should be one way.

Rapid tap doesn't fire touchesEnded

Ok, so I am hoping someone can shed some light on this. The thing is I have an app where the user can interact with a number of "pads" that are kind of like big icons, that can be dragged around on the screen. Tapping once on the pad opens it and tapping and holding brings up an alert view which asks if you want to delete it. I am using a timer to check that a user is tapping and holding and invalidating the timer in the touchesMoved and touchesEnded events. The thing is that if you tap very quickly on a pad the touchesEnded event is never fired and as such the delete dialog appears, which can get a little confusing for a user. Any thoughts on why this is?
- (void) startTouchTimer:(float)delay
{
self.touchTimer = [NSTimer scheduledTimerWithTimeInterval:delay target:self selector:#selector(touchHeld:) userInfo:nil repeats:NO];
}
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
if (touches.count == 1)
{
for(WishPad *pad in self.view.subviews)
{
if ([touch view] == pad)
{
//Animate Selection
[UIView animateWithDuration:0.03
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
pad.highlight.alpha = 0.5;
}
completion:NULL];
self.touchedPad = pad.padName;
[self startTouchTimer:0.40];
[self.view bringSubviewToFront:pad];
}
}
}
}
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.touchTimer invalidate];
UITouch *touch = [[event allTouches] anyObject];
if (touches.count == 1)
{
for(WishPad *pad in self.view.subviews)
{
if ([touch view] == pad)
{
CGPoint location = [touch locationInView:self.view];
pad.center =location;
}
}
}
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent*)event
{
[self.touchTimer invalidate];
UITouch *touch = [[event allTouches] anyObject];
if (touches.count == 1)
{
for(WishPad *pad in self.view.subviews)
{
if ([touch view] == pad)
{
//Animate deselection
[UIView animateWithDuration:0.03
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
pad.highlight.alpha = 0;
}
completion:NULL];
CGPoint location = pad.frame.origin;
NSString *position = NSStringFromCGPoint(location);
iWishAppDelegate *delegate = (iWishAppDelegate *)[[UIApplication sharedApplication] delegate];
for (Wish in [delegate.wishes objectForKey:#"<none>"])
{
if ([position isEqual:Wish.position] && [[(WishPad*)[touch view] padName] isEqualToString:Wish.name])
{
self.goToAddWish = [[AddWish alloc] initWithNibName:#"AddWish" bundle:nil];
self.goToAddWish.editWish=YES;
self.goToAddWish.hidesBottomBarWhenPushed=YES;
[self.navigationController pushViewController:self.goToAddWish animated:YES];
[self.goToAddWish editDetailText:Wish];
[self.goToAddWish release];
}
else if ([pad.padName isEqual:Wish.name])
{
Wish.position = position;
[delegate save];
}
}
}
}
}
}
- (void) touchHeld:(NSTimer*)timer
{
[self.touchTimer invalidate];
NSString *wishToDel = [NSString stringWithFormat:#"Delete %#?", self.touchedPad];
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:wishToDel message:#"Do you really want to delete this wish?" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Delete", nil];
[alertView show];
[alertView release];
}
- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == [alertView cancelButtonIndex])
{
//Lots of deleting from plist and deleting image stuff happening here
}
You can try to use UIGestureRecognizers instead.
You would have to set up the gesture recognizer for all your pads
for(WishPad *pad in self.view.subviews)
{
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(padTapped:)];
[pad addGestureRecognizer:tapRecognizer];
[tapRecognizer release];
UILongPressGestureRecognizer *pressRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(padPressed:)];
[pad addGestureRecognizer:pressRecognizer];
[pressRecognizer release];
}
and the you can handle the taps and presses
- (void)padTapped:(UITapGestureRecognizer *)recognizer {
WishPad *pad = (WishPad *)recognizer.view;
// handle tap for pad
}
- (void)padPressed:(UILongPressGestureRecognizer *)recognizer {
WishPad *pad = (WishPad *)recognizer.view;
// handle long press for pad
}
You can control how long a press should take to be recognized as a press using minimumPressDuration. But just read up on UIGestureRecognizer. It can save you a ton of work.