2010-01-04 6 views
18

Sto cercando di implementare un pizzico in/out in cima ad un UITableView, ho guardato diversi metodi tra cui questa:Osservando pinch gesti Multi-Touch in un UITableView

Similar question

Ma mentre io può creare un oggetto UIViewTouch e sovrapporlo al mio UITableView, gli eventi di scorrimento non vengono inoltrati al mio UITableView, posso ancora selezionare le celle e rispondono correttamente attivando una transizione verso un nuovo oggetto ViewController. Ma non riesco a scorrere l'UITableView nonostante i ritocchiBegan, touchMoved e toccaEnded events.

risposta

41

Questo sembra essere un problema classico. Nel mio caso ho voluto intercettare alcuni eventi nel corso di un UIWebView che non può essere sottoclassi, ecc ecc

Ho trovato che il modo migliore per farlo è quello di intercettare gli eventi utilizzando l'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 

Creare quella classe, modificare la classe del vostro UIWindow nel vostro MainWindow.xib a EventInterceptWindow, t da qualche parte impostare eventInterceptDelegate su un controller di visualizzazione che si desidera intercettare gli eventi. Esempio che intercetta un doppio tocco:

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

informazioni correlate qui: http://iphoneincubator.com/blog/windows-views/360idev-iphone-developers-conference-presentation

+0

Questo metodo funziona Ottimo ed è più pulito rispetto al metodo degli oggetti sovrapposti. Grazie! –

+0

Davvero un'ottima soluzione, cercavo qualcosa di simile per aggiungere gesti a scrollview/tableview, grazie! :) – Jaanus

+1

Soluzione eccezionale. L'ho fatto funzionare bene per alcuni mesi, catturando un gesto a doppio tocco con 3 dita. Recentemente uno dei miei colleghi più nevrotici è stato in grado di causare un incidente che sembra essere causato da questo.La traccia dello stack non mostra codice obiettivo-c, tuttavia lancia un 'EXEC_BAD_ACCESS' su' [UIScrollViewPanGestureRecognizer toccaCancelled: withEvent:] - [UIApplication _cancelTouches: withEvent: sendingTouchesCancelled: includingGestures:] '. La mia ipotesi è che il primo "3-tap" stia avviando un PanGesture ma poi uccido l'evento (non con grazia). Restituire sempre "NO" lo corregge. –

5

Nimrod ha scritto:

qualche impostare l'eventInterceptDelegate ad un controller della vista che si desidera intercettare eventi

Non ho capito subito questa affermazione. Per il beneficio di chiunque abbia avuto lo stesso problema di me, il modo in cui l'ho fatto è stato aggiungendo il seguente codice alla sottoclasse UIView che deve rilevare i tocchi.

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


Questa versione di interceptEvent: è una semplice implementazione di rilevamento pinch-to-zoom. NB. Un codice è stato preso da Beginning iPhone 3 Development di 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: Anche se questo codice ha funzionato al 100% bene nel simulatore iPhone, quando mi sono imbattuto su un dispositivo iPhone che ho incontrato strani bug relativi alla scorrimento tavolo. Se ciò accade anche a te, quindi forzare il metodo interceptEvent: per restituire NO in tutti i casi. Ciò significa che la superclasse elaborerà anche l'evento touch, ma fortunatamente questo non ha infranto il mio codice.

+0

Perché non usare 'self.view.window' in viewDidAppear? – schieferstapel