http://stackoverflow.com/questions/2003201/observing-pinch-multi-touch-gestures-in-a-uitableview

I am looking to implement a pinch in/out on top of a UITableView, I have looked at several methods including this one:

 

But while I can create a UIViewTouch object and overlay it onto my UITableView, scroll events are not being relayed to my UITableView, I can still select cells, and they respond properly by triggering a transition to a new ViewController object. But I can not scroll the UITableView despite passing the touchesBegan, touchesMoved, and touchesEnded events.

 

answer:

This seems to be a classic problem. In my case I wanted to intercept some events over a UIWebView which can't be subclassed, etc etc.

I've found that the best way to do it is to intercept the events using the UIWindow:

EventInterceptWindow.h

@protocol EventInterceptWindowDelegate
- (BOOL)interceptEvent:(UIEvent *)event; // return YES if event handled
@end


@interface EventInterceptWindow : UIWindow {
    // It would appear that using the variable name 'delegate' in any UI Kit
    // subclass is a really bad idea because it can occlude the same name in a
    // superclass and silently break things like autorotation.
    id <EventInterceptWindowDelegate> eventInterceptDelegate;
}

@property(nonatomic, assign)
    id <EventInterceptWindowDelegate> eventInterceptDelegate;

@end

EventInterceptWindow.m:

#import "EventInterceptWindow.h"

@implementation EventInterceptWindow

@synthesize eventInterceptDelegate;

- (void)sendEvent:(UIEvent *)event {
    if ([eventInterceptDelegate interceptEvent:event] == NO)
        [super sendEvent:event];
}

@end

Create that class, change the class of your UIWindow in your MainWindow.xib to EventInterceptWindow, then somewhere set the eventInterceptDelegate to a view controller that you want to intercept events. Example that intercepts a double-tap:

- (BOOL)interceptEvent:(UIEvent *)event {
    NSSet *touches = [event allTouches];
    UITouch *oneTouch = [touches anyObject];
    UIView *touchView = [oneTouch view];
    //  NSLog(@"tap count = %d", [oneTouch tapCount]);
    // check for taps on the web view which really end up being dispatched to
    // a scroll view
    if (touchView && [touchView isDescendantOfView:webView]
            && touches && oneTouch.phase == UITouchPhaseBegan) {
        if ([oneTouch tapCount] == 2) {
            [self toggleScreenDecorations];
            return YES;
        }
    }   
    return NO;
}

Related info here: http://iphoneincubator.com/blog/windows-views/360idev-iphone-developers-conference-presentation

 

 

 

another:

 

#import <UIKit/UIKit.h>
#import "EventInterceptWindow.h"

@interface ViewController : UIViewController<EventInterceptWindowDelegate>
{
    int initialDistance;
}
- (BOOL) interceptEvent:(UIEvent *) event;
@end

 

- (void) viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    // Register to receive touch events
    AppDelegate *appDelegate = (AppDelegate *) [[UIApplication sharedApplication] delegate];
    EventInterceptWindow *window = (EventInterceptWindow *) appDelegate.window;
    window.eventInterceptDelegate = self;
}
- (void) viewWillDisappear:(BOOL) animated
{
    // Deregister from receiving touch events
    AppDelegate *appDelegate = (AppDelegate *) [[UIApplication sharedApplication] delegate];
    EventInterceptWindow *window = (EventInterceptWindow *) appDelegate.window;
    window.eventInterceptDelegate = nil;
    [super viewWillDisappear:animated];
}

- (BOOL) interceptEvent:(UIEvent *) event
{
    NSSet *touches = [event allTouches];
    
    // Give up if user wasn't using two fingers
    if([touches count] != 2) return NO;
    
    UITouchPhase phase = ((UITouch *) [touches anyObject]).phase;
    CGPoint firstPoint = [[[touches allObjects] objectAtIndex:0] locationInView:self.view];
    CGPoint secondPoint = [[[touches allObjects] objectAtIndex:1] locationInView:self.view];
    
    CGFloat deltaX = secondPoint.x - firstPoint.x;
    CGFloat deltaY = secondPoint.y - firstPoint.y;
    CGFloat distance = sqrt(deltaX*deltaX + deltaY*deltaY);
    
    if(phase == UITouchPhaseBegan)
    {
        initialDistance = distance;
    }
    else if(phase == UITouchPhaseMoved)
    {
        CGFloat currentDistance = distance;
        if(initialDistance == 0) initialDistance = currentDistance;
        else if(currentDistance - initialDistance > kMinimumPinchDelta) NSLog(@"Zoom in");
        else if(initialDistance - currentDistance > kMinimumPinchDelta) NSLog(@"Zoom out");
    }
    else if(phase == UITouchPhaseEnded)
    {
        initialDistance = 0;
    }
    
    return YES;
}

 

#import <UIKit/UIKit.h>
#import "EventInterceptWindow.h"
@class ViewController;
@interface AppDelegate : UIResponder <UIApplicationDelegate>
{
    EventInterceptWindow *_window;
    ViewController *_viewController;
}
@property (strong, nonatomic) EventInterceptWindow *window;
@property (strong, nonatomic) ViewController *viewController;
@end

 

 

#import "AppDelegate.h"
#import "ViewController.h"
@implementation AppDelegate

@synthesize window = _window;
@synthesize viewController = _viewController;
- (void)dealloc
{
    [_window release];
    [super dealloc];
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    EventInterceptWindow *winTemp = [[EventInterceptWindow alloc]initWithFrame:[[UIScreen mainScreen]bounds]];
    self.window = winTemp;
    [winTemp release];
    
    ViewController *temp = [[ViewController alloc]initWithNibName:@"ViewController" bundle:nil];
    self.viewController = temp;
    [temp release];
    
    self.window.rootViewController = _viewController;
    [self.window makeKeyAndVisible];
    return YES;
}