2010-01-04 4 views
18

Ищу реализовать щепотку в/на верхней части UITableView, я смотрел на несколько методов, в том числе и этот:Наблюдая щепотку мультитач жесты в UITableView

Similar question

Но пока я может создать объект UIViewTouch и наложить его на мой UITableView, события прокрутки не будут переданы в мой UITableView, я все равно могу выбрать ячейки, и они будут правильно реагировать, инициируя переход к новому объекту ViewController. Но я не могу прокручивать UITableView, несмотря на то, что передал прикосновенияBegan, touchsMoved и касается событийEnded.

ответ

41

Это, по-видимому, классическая проблема. В моем случае я хотел бы перехватывать некоторые события по UIWebView, которые не могут быть наследником, и т.д. и т.п.

Я обнаружил, что лучший способ сделать это, чтобы перехватить события, используя 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 

Создать этот класс, изменить класс вашего UIWindow в вашем MainWindow.xib к EventInterceptWindow, т где-нибудь установите eventInterceptDelegate на контроллер вида, который вы хотите перехватить события. Пример, который перехватывает двойное нажатие:

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

Связанная информация здесь: http://iphoneincubator.com/blog/windows-views/360idev-iphone-developers-conference-presentation

+0

Этот метод работает отлично и является более чистым, чем метод наложенных объектов. Спасибо! – 2010-01-06 21:02:49

+0

Действительно отличное решение, искал что-то подобное, чтобы добавить жесты в scrollview/tableview, спасибо! :) – Jaanus

+1

Удивительное решение. У меня было хорошо работать в течение нескольких месяцев, фиксируя жест 3 красных пальцев. Недавно один из моих более невротических коллег смог вызвать катастрофу, которая, по-видимому, вызвана этим.Трассировка стека не отображает код цели-c, однако он бросает 'EXEC_BAD_ACCESS' на' [UIScrollViewPanGestureRecognizer touchsCancelled: withEvent:] - [UIApplication _cancelTouches: withEvent: отправкаTouchesCancelled: includingGestures:] '. Моя гипотеза заключается в том, что первый «3-кратный» запускает PanGesture, но затем я просто убиваю событие (не изящно). Всегда возвращающ «НЕТ» исправляет его. –

5

Нимрод писал:

где установить eventInterceptDelegate к контроллеру представления, что вы хотите перехватывать события

Я не сразу понял это утверждение. В интересах кого-то другого, у кого была такая же проблема, как и я, способ, которым я это делал, заключался в добавлении следующего кода в мой подкласс UIView, который должен обнаруживать штрихи.

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


Эта версия interceptEvent: простая реализация обнаружения пинч-на-зумом. NB. Некоторый код был взят с начала разработки iPhone 3 от 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: В то время как этот код работал 100% штраф в iPhone симулятор, когда я запустил его на устройстве iPhone я столкнулся странные ошибки, связанные с таблицей прокруткой. Если это также случается с вами, то заставьте метод interceptEvent: возвращать NO во всех случаях. Это означает, что суперкласс также обработает событие touch, но, к счастью, это не нарушило мой код.

+0

Почему бы не использовать 'self.view.window' в viewDidAppear? – schieferstapel