2009-07-30 11 views
15

Apple es realmente divertido. Quiero decir, dicen que esto funciona:¿Cuál es el truco para pasar un evento al siguiente respondedor en la cadena de respuesta?

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

Tengo un controlador de vista. Como ya sabes, View Controllers hereda de UIResponder. Ese controlador de vista crea un objeto MyView que hereda de UIView y lo agrega como una subvista a su propia vista.

Así tenemos:

Vista Controlador> tiene una vista (de forma automática)> tiene un MyView (que es un UIView).

Ahora dentro de MyView puse ese código como el anterior con un NSLog que imprime "tocado MyView". Pero reenvio el evento al siguiente respondedor, al igual que arriba. Y dentro del ViewController tengo otro método touchesBegan que solo imprime un NSLog como "controlador de vista tocado".

Ahora adivine qué: Cuando toco el MyView, se imprime "tocó MyView". Cuando toco fuera de MyView, que es la vista del VC, obtengo un "controlador de vista tocado". ¡Entonces ambos funcionan! Pero lo que no funciona es reenviar el evento. Porque ahora, en realidad, el siguiente respondedor debería ser el controlador de vista, ya que no hay nada más entremedio. Pero el método de manejo de eventos del VC nunca se llama cuando lo reenvío.

% $ &! § !!

Ideas?

Resueltas cosas raras El siguiente respondedor de MyView es la vista del controlador de vista. Eso tiene sentido, porque MyView es una subvista de eso. Pero no modifiqué esta UIView del controlador de vista. no es nada personalizado. Y no implementa ningún manejo de eventos táctiles. ¿No debería pasar el mensaje al controlador de vista? ¿Cómo podría dejarlo pasar? Si elimino el código de manejo de eventos en MyView, entonces el evento llega muy bien en el controlador de vista.

Respuesta

5

De acuerdo con similar question, su método debería funcionar.

Esto me lleva a pensar que nextResponder de su punto de vista es que no en realidad el ViewController, como sospecha.

yo añadiría una rápida NSLog en su código de reenvío para comprobar cuál es su nextResponder apunta realmente a:

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

También puede cambiar sus otros mensajes NSLog para que tipo de salida y la información de dirección:

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

touched <UIView 0x12345678>

Esto debería comenzar a diagnosticar el problema.

+0

, gracias eJames. MyView me dice que el siguiente respondedor es exactamente la vista del controlador de vista. Las direcciones de memoria coinciden perfectamente. sin embargo, este toque de Bean no se llamará. pero ahora veo que este método se invocaría en la vista del controlador de vista, pero no en el controlador de vista en sí. pero entonces, ¿este evento no continuaría burbujeando hasta que el controlador de vista de la vista no lo maneje? ¿o es otro caso especial porque lo envío manualmente? –

+0

Bueno, supongo que tiene sentido. La implementación predeterminada de 'touchesBegan:' no hace nada, así que una vez que la pasa al siguiente objeto 'UIView', simplemente termina. ¿Es factible simplemente pasar el evento táctil al viewController de forma manual? –

+0

¿Has intentado llamar '[super touchesBegan: ...]' en lugar de '[self.nextResponder touchesBegan: ...]' He visto a algunas personas usar ese método, pero no estoy seguro de qué es lo que hace. –

2

Sí, debería funcionar al 100% en caso común. Acabo de probar con el proyecto de prueba y todo parece estar bien.

He creado la aplicación basada en la vista. El uso de Interface Builder pone a UIView nuevo en la vista actual.Luego cree un nuevo archivo con la subclase de UIView y seleccione la clase recién creada para mi nueva vista. (Interface Builder-> Class identity-> Class-> MyViewClass)

Agregue toques a las funciones del controlador tanto para MyViewClass como para 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"); 
} 

veo ambos NSLogs cuando la prensa MyViewClass. ¿Usó el Interface Builder y el archivo XIB cuando cargó su ViewController o configuró la vista programáticamente con la función loadView?

1

Sé que esta publicación es antigua pero pensé compartir id porque tuve una experiencia similar. Lo arreglé estableciendo el userInteractionEnabled en NO para la vista del controlador de vista que se creó automáticamente.

4

Tuve problemas con esto, ya que mi vista personalizada era más profunda en la jerarquía de vistas. En cambio, escalé la cadena de respuesta hasta que encuentra un 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

Para hacer referencia a un controlador de vista, es necesario utilizar

[[self nextResponder] nextResponder] 

porque [self nextResponder] significa vista de un controlador de vista, y [[self nextResponder] nextResponder] significa que el controlador de vista sí, ahora usted puede conseguir el evento táctil

+0

Puede funcionar bien en iOS9 y 10, pero no funciona en iOS11 . Realmente necesita subir la cadena de respuesta hasta que llegue al viewController o tableViewController que está buscando. – ghr

1

Hoy encontré un método mejor para solucionar esta o la pregunta de esta manera.

En el suyo UITableViewCell, se puede agregar un delegado para escuchar el caso del tacto, de esta manera:

@protocol imageViewTouchDelegate 

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

@end 

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

Luego, en el suyo UITableViewController: su lata hace así:

@interface pressionTable : UITableViewController<facialViewDelegate> 

y en el .m archivo que puede implemate esta interfaz delegado, como:

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

NOTA: cuando init la célula, debe configurar el delegado, de lo contrario el delegado no es válido, se puede hacer como esto

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

}

PD: Sé que esto DOC es viejo, pero todavía añadir mi método para fijar el pregunta para que cuando las personas encuentren el mismo problema, obtengan ayuda de mi respuesta.

2

Si nos fijamos en la documentación de UIResponder la descripción dice que por defecto:

UIView implementa este método mediante la devolución del objeto UIViewController que lo gestiona (si tiene uno) o su supervista (si doesn 't);

Si su vista no devuelve el controlador de vista, debe devolver su supervista entonces (como se imaginó).

UIApplication en realidad tiene un método que se supone que debe manejar este caso de uso exactamente:

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

Dado que usted no tiene una referencia al destino, puede trabajar su camino hasta la cadena de respuesta mediante el establecimiento de destino valor como nil ya que según la documentación:

Si el objetivo es nulo, la aplicación envía el mensaje a la primera respondedor, de donde se avanza en la cadena de respuesta hasta que se maneja.

Usted puede obtener, por supuesto, el acceso a la UIApplication con su método de clase [UIApplication sharedApplication]

Más información aquí: UIApplication documents

Esta es extra, pero si es absolutamente necesario acceder al controlador de vista de hacer algo un un poco más complejo, puede subir hasta la cadena de respuesta manualmente hasta llegar al controlador de vista llamando al método nextResponder hasta que devuelva un controlador de vista. Por ejemplo:

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

a continuación, puedes echarlo como su controlador de vista y proceder hacer lo que quería hacer con ella:

UIViewController *parentVC = (UIViewController *)responder 
Cuestiones relacionadas