2010-01-04 5 views
18

ich eine Prise zu implementieren suchen in/out auf einem UITableView, ich an verschiedenen Methoden ausgesehen haben so auch hier:Beobachten kneifen Multi-Touch-Gesten in einem UITableView

Similar question

Aber während ich kann ein UIViewTouch Objekt erstellen und es auf meine UITableView überlagern, Scroll-Ereignisse werden nicht an meine UITableView weitergeleitet, ich kann immer noch Zellen auswählen, und sie reagieren richtig, indem sie einen Übergang zu einem neuen ViewController-Objekt auslösen. Aber ich kann das UITableView nicht scrollen, obwohl ich die touchesBegan, touchesMoved und touchEnded Events passiert habe.

Antwort

41

Dies scheint ein klassisches Problem zu sein. In meinem Fall habe ich einige Ereignisse über einen UIWebView abfangen wollte, die nicht unterklassiert werden können, etc etc.

Ich habe festgestellt, dass der beste Weg, es zu tun ist, um die Ereignisse mit dem UIWindow abfangen:

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 

diese Klasse erstellen, die Klasse Ihres UIWindow in Ihrem MainWindow.xib zu EventInterceptWindow, t ändern Stellen Sie event_interceptDelegate irgendwo auf einen View-Controller ein, der Ereignisse abfangen soll. Beispiel, das ein Doppeltippen ab:

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

Verwandte Informationen hier: http://iphoneincubator.com/blog/windows-views/360idev-iphone-developers-conference-presentation

+0

Diese Methode funktioniert hervorragend und ist sauberer als die Methode der überlagernden Objekte. Danke! –

+0

Wirklich tolle Lösung, war auf der Suche nach etwas wie das Hinzufügen von Gesten zu scrollview/tableview, danke! :) – Jaanus

+1

Tolle Lösung. Ich habe es seit ein paar Monaten gut laufen jetzt eine 3-Finger-Doppeltipp-Geste erfassen. Kürzlich konnte einer meiner eher neurotischen Kollegen einen Absturz verursachen, der dadurch verursacht zu sein scheint.Der Stack-Trace zeigt keinen objective-c-Code, jedoch wird eine 'EXEC_BAD_ACCESS' auf' [UIScrollViewPanGestureRecognizer touchesCancelled: withEvent:] - [UIApplication _cancelTouches: withEvent: sendingTouchesCancelled: includingGestures:] 'geworfen. Meine Hypothese ist, dass der erste "3-Tap" eine PanGesture startet, aber dann töte ich das Event (nicht anmutig). Wenn Sie immer 'NO' zurückgeben, wird es repariert. –

5

Nimrod schrieb:

irgendwo setzen Sie den eventInterceptDelegate auf einen View-Controller, die Sie mögen Ereignisse abfangen

Ich habe diese Aussage nicht sofort verstanden. Zum Vorteil für alle anderen, die das gleiche Problem hatten wie ich, habe ich den folgenden Code zu meiner UIView-Unterklasse hinzugefügt, der Berührungen erkennen muss.

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


Diese Version von interceptEvent: ist eine einfache Implementierung von Pinch-to-Zoom-Erkennung. NB. Einige Code wurde von Anfang iPhone 3 Entwicklung von Apress genommen.

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: Während dieser Code 100% fein im iPhone-Simulator gearbeitet, wenn ich es auf einem iPhone Gerät lief begegnete ich seltsame Fehler auf dem Tisch eine Rolle im Zusammenhang stehen. Wenn dies auch bei Ihnen der Fall ist, zwingen Sie die Methode interceptEvent:, in allen Fällen NEIN zurückzugeben. Dies bedeutet, dass die Superklasse auch das Berührungsereignis verarbeiten wird, aber glücklicherweise hat dies meinen Code nicht zerstört.

+0

Warum nicht 'self.view.window' in viewDidAppear verwenden? – schieferstapel