Observing pinch multi-touch gestures in a UITableView

后端 未结 2 2035
Happy的楠姐
Happy的楠姐 2020-11-27 02:17

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

Similar question

But while I can cre

相关标签:
2条回答
  • 2020-11-27 03:01

    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

    0 讨论(0)
  • 2020-11-27 03:01

    Nimrod wrote:

    somewhere set the eventInterceptDelegate to a view controller that you want to intercept events

    I didn't immediately understand this statement. For the benefit of anyone else who had the same problem as me, the way I did it was by adding the following code to my UIView subclass which must detect touches.

    - (void) viewDidAppear:(BOOL)animated
    {
        [super viewDidAppear:animated];
    
        // Register to receive touch events
        MyApplicationAppDelegate *appDelegate = (MyApplicationAppDelegate *) [[UIApplication sharedApplication] delegate];
        EventInterceptWindow *window = (EventInterceptWindow *) appDelegate.window;
        window.eventInterceptDelegate = self;
    }
    
    
    - (void) viewWillDisappear:(BOOL) animated
    {
        // Deregister from receiving touch events
        MyApplicationAppDelegate *appDelegate = (MyApplicationAppDelegate *) [[UIApplication sharedApplication] delegate];
        EventInterceptWindow *window = (EventInterceptWindow *) appDelegate.window;
        window.eventInterceptDelegate = nil;
    
        [super viewWillDisappear:animated];
    }
    
    
    - (BOOL) interceptEvent:(UIEvent *) event
    {
        NSLog(@"interceptEvent is being called...");
        return NO;
    }
    


    This version of interceptEvent: is a simple implementation of pinch-to-zoom detection. NB. Some code was taken from Beginning iPhone 3 Development by Apress.

    CGFloat initialDistance;
    
    - (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;
    }
    


    Edit: While this code worked 100% fine in the iPhone simulator, when I ran it on an iPhone device I encountered strange bugs related to the table scrolling. If this also happens to you, then force the interceptEvent: method to return NO in all cases. This means that the superclass will also process the touch event, but fortunately this did not break my code.

    0 讨论(0)
提交回复
热议问题