Pergunta

Eu estou olhando para implementar uma pitada in / out em cima de um UITableView, eu olhei para vários métodos, incluindo esta:

pergunta homóloga

Mas enquanto eu posso criar um objeto UIViewTouch e sobrepor-lo no meu UITableView, eventos de rolagem não estão sendo retransmitida ao meu UITableView, eu ainda pode selecionar células, e eles respondem adequadamente pelo desencadeamento de uma transição para um novo objeto ViewController. Mas eu não posso rolar a UITableView apesar de passar a touchesBegan, touchesMoved e touchesEnded eventos.

Foi útil?

Solução

Este parece ser um problema clássico. No meu caso eu queria interceptar alguns eventos ao longo de um UIWebView que não pode ser uma subclasse, etc etc.

Eu descobri que a melhor maneira de fazer isso é para interceptar os eventos usando o 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

Criar essa classe, alterar a classe da sua UIWindow em sua MainWindow.xib para EventInterceptWindow, então em algum lugar definir o eventInterceptDelegate a um controlador de vista que deseja eventos interceptar. Exemplo que intercepta um toque duplo:

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

Informações relacionadas aqui: http://iphoneincubator.com/blog/windows-views/360idev -iphone-developers-conferência de apresentação

Outras dicas

Nimrod escreveu:

em algum lugar definir o eventInterceptDelegate a um controlador de vista que deseja eventos interceptar

Eu não imediatamente compreender esta declaração. Para o benefício de qualquer outra pessoa que teve o mesmo problema que eu, a maneira que eu fiz foi por adicionando o seguinte código aos meus subclasse UIView que deve detectar toques.

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


Esta versão do interceptEvent: é uma implementação simples de detecção de pinch-to-zoom. NB. Algum código foi tomada a partir Começando iPhone Desenvolvimento 3 por 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: Embora este código funcionou 100% bem no simulador iPhone, quando eu corri-lo em um dispositivo iPhone eu encontrei bugs estranhos relacionados com a rolagem mesa. Se isso também acontece com você, em seguida, forçar o método interceptEvent: para retornar NO em todos os casos. Isto significa que a superclasse também irá processar o evento de toque, mas felizmente isso não quebrar meu código.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top