2009-07-30 11 views
15

Apple è davvero divertente. Voglio dire, dicono che questo funziona:Qual è il trucco per passare un evento al prossimo risponditore nella catena di risposta?

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 
    UITouch* touch = [touches anyObject]; 
    NSUInteger numTaps = [touch tapCount]; 
    if (numTaps < 2) { 
     [self.nextResponder touchesBegan:touches withEvent:event]; 
    } else { 
     [self handleDoubleTap:touch]; 
    } 
} 

Ho un controller di visualizzazione. Come sai, View Controller eredita da UIResponder. Quel Controller Vista crea un oggetto MyView che eredita da UIView e lo aggiunge come sottoview alla propria vista.

Quindi abbiamo:

View Controller> ha una vista (automaticamente)> ha un MyView (che è un UIView).

Ora all'interno di MyView ho inserito il codice come sopra con un NSLog che stampa "touched MyView". Ma inoltro l'evento al prossimo risponditore, proprio come sopra. E all'interno del ViewController ho un altro tocco: metodo Began che stampa un NSLog a la "touched view controller".

Ora indovina cosa: Quando tocco MyView, viene stampato "MyView" toccato. Quando tocco fuori da MyView, che è la vista del VC, ricevo un "controller di visualizzazione toccato". Quindi entrambi funzionano! Ma ciò che non funziona è l'inoltro dell'evento. Perché ora, in realtà, il prossimo risponditore dovrebbe essere il controller della vista, dal momento che non c'è nient'altro in mezzo. Ma il metodo di gestione degli eventi del VC non viene mai chiamato quando lo inoltro.

% $ &! § !!

Idee?

Capito roba strana prossimo risponditore di MyView è la vista del controller della vista. Questo ha senso, perché MyView è una sottoview di questo. Ma non ho modificato questo UIView dal controller della vista. non è niente di personalizzato E non implementa alcuna gestione di eventi touch. Il messaggio non dovrebbe essere trasmesso al controller della vista? Come potrei lasciarlo passare? Se rimuovo il codice di gestione degli eventi in MyView, l'evento arriva correttamente nel controller della vista.

risposta

5

Secondo un similar question, il metodo dovrebbe funzionare.

Questo mi porta a pensare che di nextResponder tuo punto di vista è non in realtà il ViewController, come si sospetta.

vorrei aggiungere un rapido NSLog nel codice inoltro per verificare che cosa il vostro nextResponder punti davvero:

if (numTaps < 2) { 
    NSLog(@"nextResponder = %@", self.nextResponder); 
    [self.nextResponder touchesBegan:touches withEvent:event]; 
} 

È inoltre possibile modificare le altre messaggi NSLog in modo che il tipo di output e indirizzo:

NSLog(@"touched %@", self); 

touched <UIView 0x12345678>

Questo dovrebbe iniziare a diagnosticare il problema.

+0

eJames Grazie. MyView mi dice che il prossimo risponditore è esattamente la vista del controller della vista. Gli indirizzi di memoria corrispondono perfettamente. tuttavia, questo tocca Began non verrà chiamato. ma ora vedo che questo metodo verrebbe invocato sulla vista del controller della vista, ma non sul controller stesso della vista. ma allora, questo evento non continuerà a ribollire fino al controller di vista della vista non lo gestisce? o è un altro caso speciale perché lo invio manualmente? –

+0

Beh, suppongo che abbia senso. L'implementazione predefinita di "touchesBegan:" non fa nulla, quindi una volta passata al prossimo oggetto 'UIView', termina semplicemente. È possibile passare manualmente l'evento touch al ViewController manualmente? –

+0

Hai provato a chiamare '[super touchesBegan: ...]' invece di '[self.nextResponder toccaBegan: ...]' Ho visto alcune persone che usano quel metodo, ma non sono sicuro di cosa faccia. –

2

Sì, dovrebbe funzionare al 100% nel caso comune. Ho appena provato con il progetto di test e tutto sembra essere ok.

Ho creato un'applicazione basata su vista. Usando Interface Builder metti nuovo UIView alla vista attuale.Quindi crea un nuovo file con sottoclasse di UIView e seleziona la classe appena creata per la mia nuova vista. (Interface Builder-> Class identity-> Class-> MyViewClass)

Aggiungi tocchi funzioni di gestione sia per MyViewClass e UIViewController.

// MyViewClass

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 
NSLog(@"myview touches"); 
[self.nextResponder touchesBegan:touches withEvent:event]; 
} 

// ViewController

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 
    NSLog(@"controller touches"); 
} 

vedo entrambi NSLogs quando si preme MyViewClass. Hai usato Interface Builder e il file XIB durante il caricamento di ViewController o hai impostato la visualizzazione programmatica con la funzione loadView?

1

So che questo post è vecchio ma pensavo che l'ID condividesse perché avevo un'esperienza simile. L'ho risolto impostando userInteractionEnabled su NO per la vista del controller di visualizzazione che era stato creato automaticamente.

4

Ha avuto problemi con questo, poiché la mia visualizzazione personalizzata era più profonda nella gerarchia della vista. Invece, ho scalato la catena di risposta fino a quando non trova uno UIViewController;

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 
    // Pass to top of chain 
    UIResponder *responder = self; 
    while (responder.nextResponder != nil){ 
     responder = responder.nextResponder; 
     if ([responder isKindOfClass:[UIViewController class]]) { 
      // Got ViewController 
      break; 
     } 
    } 
    [responder touchesBegan:touches withEvent:event]; 
} 
2

Per fare riferimento a un controller di vista, è necessario utilizzare

[[self nextResponder] nextResponder] 

perché [self nextResponder] significa vista di un controller della vista, e [[self nextResponder] nextResponder] significa che il controller della vista stessa, ora è possibile ottenere l'evento di tocco

+0

Potrebbe funzionare in iOS9 e 10 ma non funziona in iOS11 . Hai davvero bisogno di scalare la catena di risposta fino a raggiungere la viewController o tableViewController che stai cercando. – ghr

1

Oggi ho trovato un metodo migliore per risolvere questo o la domanda come questa.

Nel tuo UITableViewCell, è possibile aggiungere un delegato per ascoltare l'evento di tocco, in questo modo:

@protocol imageViewTouchDelegate 

-(void)selectedFacialView:(NSInteger)row item:(NSInteger)rowIndex; 

@end 

@property(nonatomic,assign)id<imageViewTouchDelegate>delegate; 

Poi nella tua UITableViewController: tuo può fare in questo modo:

@interface pressionTable : UITableViewController<facialViewDelegate> 

e nel .m file è possibile collegare questa interfaccia delegato come:

-(void)selectedFacialView:(NSInteger)row item:(NSInteger)rowIndex{ 
//TO DO WHAT YOU WANT} 

NOTA: quando si inizia la cella, è necessario impostare il delegato, in caso contrario il delegato non è valido, si può fare in questo modo

- (UITableViewCell *)tableView:(UITableView *)tableView 
    cellForRowAtIndexPath:(NSIndexPath *)indexPath { 

static NSString *CellIdentifier = @"Cell"; 

pressionCell *cell = (pressionCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
if (cell == nil) { 
    cell = [[pressionCell alloc]initWithFrame:CGRectMake(0, 0, 240, 40)]; 
} 

cell.delegate = self; 

}

PS: So che questo DOC è vecchio, ma ho ancora aggiungere il mio metodo per risolvere il domanda così quando le persone incontrano lo stesso problema, riceveranno aiuto dalla mia risposta.

2

Se si guarda la documentazione della UIResponder la descrizione dice che per default:

UIView implementa questo metodo restituendo l'oggetto UIViewController che lo gestisce (se ne ha uno) o il suo superview (se doesn 't);

Se la vista non restituisce il controller della vista, deve restituire la sua superview (come si è capito).

UIApplication ha in realtà un metodo che dovrebbe gestire questo caso d'uso esattamente:

- (BOOL)sendAction:(SEL)action 
       to:(id)target 
       from:(id)sender 
      forEvent:(UIEvent *)event 

Dal momento che non si dispone di un riferimento al target, si può lavorare il vostro senso della catena risponditore impostando bersaglio valore come nil poiché, secondo la documentazione:

Se il target è pari a zero, l'applicazione invia il messaggio al primo soccorritore, da cui si svilupperà lungo la catena risponditore fino a quando non viene gestito.

Ovviamente si può ottenere l'accesso al UIApplication con il suo metodo di classe [UIApplication sharedApplication]

Maggiori informazioni qui: UIApplication documents

Questa è extra, ma se è assolutamente necessario accedere al controller della vista di fare qualcosa di un un po 'più complesso, è possibile risalire manualmente la catena di risposta fino a raggiungere il controller di visualizzazione chiamando il metodo nextResponder finché non restituisce un controller di visualizzazione. Per esempio:

UIResponder *responder = self; 
while ([responder isKindOfClass:[UIView class]]) 
    responder = [responder nextResponder]; 

allora si può solo lanciare come vostro controller della vista e procedere fare quello che voleva fare con esso:

UIViewController *parentVC = (UIViewController *)responder 
Problemi correlati