¿Cómo deshabilitar la entrada táctil para todas las vistas excepto la vista superior?

Tengo una vista con múltiples subvistas. Cuando un usuario toca una subvista, la subvista se expande en tamaño para cubrir la mayor parte de la pantalla, pero algunas de las otras subvistas todavía son visibles debajo.

Quiero que mi aplicación ignore los toques en las otras subvistas cuando una de las subvistas se “expande” de esta manera. ¿Hay una manera simple de lograr esto? Puedo escribir código para manejar esto, pero esperaba que hubiera una forma integrada más simple.

Espero que esto ayude…

[[yourSuperView subviews] makeObjectsPerformSelector:@selector(setUserInteractionEnabled:) withObject:[NSNumber numberWithBool:FALSE]]; 

que deshabilitará la interacción del usuario de las subvistas inmediatas de una vista … Luego, dale a la interacción del usuario la única vista que deseas

 yourTouchableView.setUserInteraction = TRUE; 

EDITAR:

Parece que en iOS deshabilitar userInteraction en una vista padre no deshabilita userInteraction en sus hijos … Por lo tanto, el código anterior (me refiero al que tiene makeObjectsPerformSelector: solo funcionará para deshabilitar userInteraction de las subvistas inmediatas de un padre …

Vea la respuesta del usuario madewulf, que recursivamente obtiene todas las subvistas y deshabilita la interacción del usuario de todas ellas. O si necesita deshabilitar la interacción de usuario de esta vista en muchos lugares del proyecto, puede categorizar UIView para agregar esa característica. Algo así lo hará …

 @interface UIView (UserInteractionFeatures) -(void)setRecursiveUserInteraction:(BOOL)value; @end @implementation UIView(UserInteractionFeatures) -(void)setRecursiveUserInteraction:(BOOL)value{ self.userInteractionEnabled = value; for (UIView *view in [self subviews]) { [view setRecursiveUserInteraction:value]; } } @end 

Ahora puedes llamar

 [yourSuperView setRecursiveUserInteraction:NO]; 

También la sugerencia de user @ lxt de agregar una vista invisible sobre todas las vistas es otra forma de hacerlo.

Hay un par de formas de hacer esto. Podrías iterar a través de todas tus otras subvistas y establecer userInteractionEnabled = NO , pero esto es menos que ideal si tienes muchas otras vistas (después de todo, tendrías que volver a cambiarlas todas).

La forma en que hago esto es crear una UIView invisible que es del tamaño de la pantalla completa que ‘bloquea’ todos los toques para ir a las otras vistas. A veces esto es literalmente invisible, otras veces puedo configurarlo en negro con un valor alfa de 0.3 o más.

Cuando expandes tu subvista principal para llenar la pantalla, puedes agregar este UIView ‘bloqueante’ (usando insertSubview: belowSubview: . Cuando minimiza su subvista expandida, puede eliminar la UIView invisible de su jerarquía.

Así que no está completamente integrado, pero creo que es el enfoque más simple. No estoy seguro de si eso era lo que ya estabas pensando, con suerte fue de alguna ayuda.

Tenga cuidado con el código dado como solución aquí por Krishnabhadra:

 [[yourSuperView subviews]makeObjectsPerformSelector:@selector(setUserInteractionEnabled:) withObject:[NSNumber numberWithBool:FALSE]]; 

Esto no funcionará en todos los casos porque [sus subvistasSuperView] solo proporciona las subvistas directas de la supervista. Para que funcione, deberá iterar recursivamente en todas las subvistas:

 -(void) disableRecursivelyAllSubviews:(UIView *) theView { theView.userInteractionEnabled = NO; for(UIView* subview in [theView subviews]) { [self disableRecursivelyAllSubviews:subview]; } } -(void) disableAllSubviewsOf:(UIView *) theView { for(UIView* subview in [theView subviews]) { [self disableRecursivelyAllSubviews:subview]; } } 

Ahora una llamada a disableAllSubviewsOf hará lo que usted quería hacer.

Si tiene una gran cantidad de vistas, la solución por lxt es probablemente mejor.

Haría esto al poner un botón transparente personalizado con el mismo marco que la superView . Y luego, sobre ese botón, pondría una vista que debería aceptar los toques del usuario. El botón se tragará todos los toques y las vistas detrás de él no recibirán ningún evento táctil, pero la vista en la parte superior del botón recibirá los toques normalmente.

Algo como esto:

 - (void)disableTouchesOnView:(UIView *)view { UIButton *ghostButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, view.frame.size.width, view.frame.size.height)]; [ghostButton setBackgroundColor:[UIColor clearColor]]; ghostButton.tag = 42; // Any random number. Use #define to avoid putting numbers in code. [view addSubview:ghostButton]; } 

Y un método para habilitar parentView .

 - (void)enableTouchesOnView:(UIView *)view { [[view viewWithTag:42] removeFromSuperview]; } 

Por lo tanto, para deshabilitar todas las vistas en el parentViev detrás de su yourView , yo haría esto:

 YourView *yourView = [[YourView alloc] initWithCustomInitializer]; // It is important to disable touches on the parent view before adding the top most view. [self disableTouchesOnView:parentView]; [parentView addSubview:yourView]; 

Solo parentView.UserInteractionEnabled = NO hará el trabajo. La vista padre deshabilitará la interacción del usuario en todas las subvistas de la vista. Pero habilitar no habilita todas las subvistas (por defecto, UIImageView no es interactuable). De modo que es fácil encontrar la vista padre y usar el código anterior, y no hay necesidad de iterar todas las subvistas para realizar un selector.

Daré mis 2 centavos a este problema. Iterativamente ejecuta userInteractionEnabled = false, es de una sola manera. Otra forma será agregar una UIView como la siguiente.

EZEventEater.h

 #import  @interface EZEventEater : UIView @end 

EZEventEater.m

 #import "EZEventEater.h" @implementation EZEventEater - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // Initialization code self.backgroundColor = [UIColor clearColor]; self.userInteractionEnabled = false; } return self; } - (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { //EZDEBUG(@"eater touched"); } - (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { } - (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { } 

En su código, agrega la vista EZEventEater para cubrir todas las vistas que puedan bloquear el evento táctil. Siempre que desee bloquear el evento táctil a esas vistas, simplemente llame

 eater.userInteractionEnabled = YES; 

Espero que esto sea útil.

Agregue un TapGestureRecognizer a su “vista de fondo” (la translúcida que “difumina” su interfaz normal) y configúrelo como “Cancela toques en la vista”, sin agregar una acción.

 let captureTaps = UITapGestureRecognizer() captureTaps.cancelsTouchesInView = true dimmedOverlay?.addGestureRecognizer(captureTaps) 

setUserInteractionEnabled = NO en la vista que desea deshabilitar

Para mi aplicación, creo que será suficiente desactivar la navegación a otras tabs de la aplicación (durante un tiempo limitado, mientras estoy procesando):

 self.tabBarController.view.userInteractionEnabled = NO; 

Además, deshabilité el controlador de vista actual–

 self.view.userInteractionEnabled = NO; 

(Y, dicho sea de paso, las soluciones recursivas propuestas aquí tuvieron efectos extraños en mi aplicación. La desactivación parece funcionar bien, pero la reactivación tiene efectos extraños: algunos de los UI no se cambiaron de nombre).

Tuve el mismo problema, pero las soluciones anteriores no ayudaron. Entonces noté que llamar a super.touchesBegan(...) era el problema. Después de eliminar esto, el evento solo fue manejado por la vista más alta.

Espero que esto sea de ayuda para cualquiera.