2011-01-07 10 views
35

Hoy en mi tiempo creativo hice una investigación bastante completa sobre cómo robar toques de un UIScrollView y enviarlos instantáneamente a una subvista específica, manteniendo el comportamiento predeterminado para el resto de la vista de desplazamiento. Considere tener un UIPickerView dentro de una UITableView. El comportamiento predeterminado es que si arrastra su dedo sobre la vista del selector, la vista de desplazamiento se desplazará y la vista del selector permanecerá sin cambios.Cómo robar toques de UIScrollView?

Lo primero que intenté fue anular

- (BOOL)touchesShouldCancelInContentView:(UIView *)view 

y simplemente no permite la UIScrollView para cancelar toques dentro de la vista selector. Esto funciona, pero tiene un efecto secundario desagradable. Desea que la vista del selector responda de inmediato y, por lo tanto, tendrá que establecer delaysContentTouches en NO. El problema es que no desea que el resto de la vista de tabla responda de inmediato, porque si lo hace, la celda de la vista de tabla siempre se resaltará durante unos pocos milisegundos antes de que comience el desplazamiento.

La segunda cosa que intenté fue anular

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

porque había leído que la vista de desplazamiento siempre vuelve en sí, por lo que va a "robar" los toques de sus subvistas y luego enviarlos a la subvista si no fueran de interés para la vista de desplazamiento. Sin embargo, esto ya no es verdad. Implementación predeterminada de UIScrollView de hitTest: withEvent: en realidad devuelve la subvista que debería recibir el toque. En cambio, usa reconocedores de gestos para interceptar los toques.

Así que la tercera cosa que intenté fue implementar mi propio reconocedor de gestos y hacer que fallara si el toque estaba fuera de la vista del selector y de lo contrario tendría éxito. Entonces me puse todos los reconocedores gesto de la vista de desplazamiento para fallar a menos que mi gesto no reconocedor usando el siguiente código:

for (UIGestureRecognizer * gestureRecognizer in self.tableView.gestureRecognizers) 
{ 
    [gestureRecognizer requireGestureRecognizerToFail:myRecognizer]; 
} 

Esto, de hecho, robar los toques desde el punto de vista de desplazamiento, pero la vista selector no los recibe. Así que, aunque tal vez podría simplemente enviar todos los toques que mi gesto reconocedor recibe a través de este código:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    for (UITouch *touch in touches) 
     [touch.view touchesBegan:touches withEvent:event]; 
} 

El código anterior es una versión simplificada. También me aseguro de que la vista sea una vista de selector (o una de sus subvistas) y establezco el estado apropiado para el reconocedor de gestos como mencioné anteriormente. También hice lo mismo para cancelar, finalizar y moverme. Sin embargo, la vista del selector aún no respondía.

También intenté una última cosa antes de volver a mi trabajo habitual. Durante mi extensa googlear leí que UIScrollViews anidados mágicamente trabajaron desde 3.x, así que traté de poner mi punto de vista dentro de un selector de UIScrollView anidada y establezca las siguientes propiedades en él:

scrollView.delaysContentTouches = NO; 
scrollView.canCancelContentTouches = NO; 

Como era de esperar el rollo externa view no trató la vista de desplazamiento interior de forma diferente a la vista del selector, por lo que la vista de desplazamiento interior no recibió los toques. Pensé que era una posibilidad remota, pero fue lo suficientemente simple de implementar, así que pensé que valía la pena intentarlo.

Lo que sé es que UIScrollView tiene un reconocedor de gestos llamado UIScrollViewDelayedTouchesBeganGestureRecognizer que intercepta los toques y los envía a la subvista apropiada después de 150 (?) Ms. Estoy pensando que debería poder escribir un reconocedor similar que haga que los reconocedores predeterminados de la vista de desplazamiento fallen y, en lugar de demorar los toques, los envíe inmediatamente a la vista del selector.Entonces, si alguien sabe cómo escribir un reconocedor, por favor avíseme y si tiene otra solución al problema, puede compartirlo también.

Gracias por leer toda la pregunta e incluso si no sabe la respuesta, todavía podría votar la pregunta para que reciba más atención (con suerte de alguien que pueda responderla). ¡Gracias! :)

Respuesta

32

A veces tiene que hacer la pregunta antes de que pueda encontrar la respuesta. Dan Ray tuvo un problema similar y lo resolvió con una solución muy diferente.

- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event 
{ 
    UIView* result = [super hitTest:point withEvent:event]; 

    if ([result.superview isKindOfClass:[UIPickerView class]]) 
    { 
     self.scrollEnabled = NO; 
    } 
    else 
    { 
     self.scrollEnabled = YES;  
    } 
    return result; 
} 

He probado el código y funciona bien para mí también. Sin embargo, esto no está robando toques de la vista de desplazamiento, por lo que si alguien sabe cómo robar toques realmente sería genial.

Fuente: UIPickerView inside UITableView.tableFooterView doesn't receive drag touches

+0

Dado que esto todavía es la única respuesta, voy a aceptarlo como mi respuesta, pero si tienes una mejor solución, ¡no dudes en compartirla! –

+0

Esta es mi solución preferida. Es delgado y malo y simplemente funciona. ¡Muchas gracias! – DrMickeyLauer

+1

Excelente, para mis necesidades lo cambié a '([result isKindOfClass: [UITableView class]] || [result.superview isKindOfClass: [UITableView class]] || [result.superview isKindOfClass: [UITableViewCell class]]) ' – Diziet

Cuestiones relacionadas