2009-05-18 10 views
7

¿Alguien puede ayudar a solucionar un noob? Publiqué este problema en varios foros y no recibí ninguna respuesta, mientras que muchas búsquedas de otras respuestas han aparecido en stackOverflow, así que espero que este sea el lugar.UIScrollView toca frente a la subvista toca

Tengo un BeachView.h (subclase de UIScrollView, imagen de una playa de arena) cubierto con un número aleatorio de Stone.h (subclase de UIImageView, un PNG aleatorio de una piedra, userInteractionEnabled = YES para aceptar toques)

Si el usuario toca y se mueve en la playa, debería desplazarse. Si el usuario toca una piedra, debe llamar al método "piedra tocada". Si el usuario toca la playa donde no hay piedra, debe llamar al método "Tocó Playa".

Ahora, me doy cuenta de que esto suena muy simple. Todo el mundo y todo me dice que si hay algo en un UIScrollView que acepta toques debe pasarle el control. Así que cuando toco y arrastro, debería desplazarse; pero si toco, y está en una piedra, debería ignorar los grifos de la playa y aceptar grifos de piedra, ¿sí?

Sin embargo, parece que ambas vistas están aceptando el toque y llamando tanto a touchStone como a TouchBeach. Además, el toque de la playa se produce primero, por lo que ni siquiera puedo poner un indicador de tipo "if touchedStone then not run touchedBeach".

Aquí hay algunos códigos. En BeachView.m


- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 
    if (self.decelerating) { didScroll = YES; } 
     else { didScroll = NO; } 

    UITouch *touch = [[event allTouches] anyObject]; 
    CGPoint touchLocation = [touch locationInView:touch.view]; 
    NSLog(@"touched beach = %@", [touch view]); 
    lastTouch = touchLocation; 
    [super touchesBegan:touches withEvent:event]; 
} 

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { 
    didScroll = YES; 
    [super touchesMoved:touches withEvent:event]; 
} 

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { 
    if (didScroll == NO && isPaused == NO) { 
      [self touchedBeach:YES location:lastTouch]; 
    } 
    [super touchesEnded:touches withEvent:event]; 
} 

En Stone.m


-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 
    [parent stoneWasTouched]; // parent = ivar pointing from stone to beachview 
} 

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { 
    UITouch *touch = [[event allTouches] anyObject]; 
    CGPoint touchLocation = [touch locationInView:touch.view]; 
    NSLog(@"touched stone = %@", [touch view]); 
    [parent touchedStone:YES location:touchLocation]; 
} 

Después de un grifo de piedra, Mi NSLog se parece a esto:


Touched beach = <BeachView: 0x1276a0> 
ran touchedBeach 
Touched Stone = <Stone: 0x1480c0> 
ran touchedStone 

Por lo que es realmente ejecuta ambos. Lo que es aún más extraño es que si tomo los toques BeGo y Toques Salidos de Stone.m pero dejo userInteractionEnabled = YES, el beachView registra ambos toques, pero devuelve la Piedra como la vista que tocó (la segunda vez).


Touched beach = <BeachView: 0x1276a0> 
ran touchedBeach 
Touched beach = <Stone: 0x1480c0> 
ran touchedBeach 

Así que POR FAVOR, he estado tratando de ordenar esto por días. ¿Cómo lo hago para que una piedra golpeada solo llame a Piedra y una playa golpeada solo llame a Playa? ¿Dónde estoy equivocado?

Respuesta

2

Antes de iPhone OS 3.0, el método hitTest: withEvent: de UIScrollView siempre devuelve self para que reciba el UIEvent directamente, solo lo reenvía a la subvista apropiada si determina que no está relacionado con el desplazamiento o el zoom.

que no podía comentar sobre iPhone OS 3.0 ya que es bajo NDA, pero compruebe que el "iPhone SDK Notas de la versión para el iPhone OS 3.0 beta 5" :)

Si es necesario apuntar a pre-3.0, podría anular hitTest: withEvent: en BeachView y establecer una bandera para ignorar el siguiente toque de playa si el CGPoint está realmente en una piedra.

¿Pero ha intentado simplemente mover sus llamadas a [super touches *: withEvent:] desde el final de sus métodos reemplazados hasta el comienzo? Esto podría causar que el golpe de piedra ocurra primero.

+0

me mudé [muy] para el inicio de los métodos y que hizo una diferencia. Todavía registra dos toques, pero al menos ahora dice 1-startedBeach 2-startedStone 3-endedBeach 4-endedStone, por lo que hay tiempo para hacer estallar una bandera allí. Estaba mirando HitTest pero cuando comenzó a hablar de CAlayers vs UIviews me pareció un libro que simplemente no estaba listo para abrir. Le daré otra oportunidad. Gracias Hatfinch, -k. –

3

Es verdad, iPhone SDK 3.0 y más, no pase toques a -touchesBegan: y - touchesEnded: ** UIScrollview ** métodos de subclase más.Puede utilizar los métodos touchesShouldBegin y touchesShouldCancelInContentView que no son lo mismo.

Si realmente desea obtener estos toques, tenga uno truco que lo permitan.

En su subclase de UIScrollView reemplazar el método hitTest así:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { 

    UIView *result = nil; 
    for (UIView *child in self.subviews) 
    if ([child pointInside:point withEvent:event]) 
     if ((result = [child hitTest:point withEvent:event]) != nil) 
     break; 

    return result; 
} 

Esto pasará a la subclase esto afecta, sin embargo no se puede cancelar los toques de UIScrollView superclase.

0

He tenido un problema similar con un simpleView y se añade a una scrollView, y cada vez que tocaba el simpleView, la scrollView utiliza para obtener el tacto y el lugar de la simpleview, la scrollView se movió. Para evitar esto, desactivé el directorio del scrollView cuando el usuario tocó el simpleView y, de lo contrario, el desplazamiento está habilitado.

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { 

    UIView *result = [super hitTest:point withEvent:event] ; 
    if (result == simpleView) 
    { 
     scrollView.scrollEnabled = NO ; 
    } 
    else 
    { 
     scrollView.scrollEnabled = YES ; 
    } 

    return result ; 

} 
Cuestiones relacionadas