2011-02-09 13 views
20

Tengo un controlador de visualización (con un UIWebView) que presento en el estilo Hoja de formulario. Tengo que colocar un botón "Listo" en la barra de columnas de UIT de la vista en el Controlador de vistas para que se descarte. Pero, dado que presentarlo en el estilo "Hoja de formulario" deja mucho espacio sin usar fuera de la vista del controlador de vista ... Estaba vagando ... ¿Hay alguna manera de detectar un toque fuera de la vista? en esa área "gris"? Gracias de antemanocómo descartar un controlador de vista modal presentado como "Hoja de formulario" cuando se produce un toque fuera de la hoja de formulario?

+1

solución mucho más sencilla aquí: http: // stackoverflow.com/questions/2623417/iphone-sdk-dismissing-modal-viewcontrollers-on-ipad-by-click-outside-of-it – onekiloparsec

+0

@ Cédric Esa solución no es lo suficientemente buena para nuestro caso de uso. Agregue un popover que se extiende más allá de los límites de la vista, y bam. Esa solución se rompe. – Mazyod

Respuesta

18

En iOS 4.2, la jerarquía de vistas de una aplicación basada en el controlador de navegación con una hoja de formulario modal es la siguiente durante viewWillAppear:. Una vez que aparece la vista modal, UITransitionView ha sido reemplazado por un UIDropShadowView que contiene la jerarquía de vista modal.

UIWindow 
    UILayoutContainerView (regular hierarchy) 
    UIDimmingView 
    UITransitionView 

de Apple advierten en contra de confiar en los subvistas de construidas en puntos de vista, ya que se consideran privadas y pueden cambiar en futuras versiones. Esto podría potencialmente romper tu aplicación.

Enfoque 1
Podemos insertar una visión transparente entre los dos últimos subvistas de ventana, y haga que sea responder al tacto eventos desestimando el formulario modal.

Esta implementación comprueba que la jerarquía de vistas de la ventana sea la esperada y silenciosamente no hará nada si no lo hace.

Cree y use DismissingView desde viewWillAppear: en el controlador de vista modal.

DismissingView *dismiss = [[DismissingView alloc] initWithFrame:window.frame 
          selector:@selector(dismissView:) target:self]; 
[dismiss addToWindow:window]; 
[dismiss release]; 

Y la implementación.

@interface DismissingView : UIView { 
} 

@property (nonatomic, retain) id target; 
@property (nonatomic) SEL selector; 

- (id) initWithFrame:(CGRect)frame target:(id)target selector:(SEL)selector; 

@end 
@implementation DismissingView 

@synthesize target; 
@synthesize selector; 

- (id) initWithFrame:(CGRect)frame target:(id)target selector:(SEL)selector 
{ 
    self = [super initWithFrame:frame]; 

    self.opaque = NO; 
    self.backgroundColor = [UIColor clearColor]; 
    self.selector = selector; 
    self.target = target; 

    return self; 
} 

- (void) addToWindow:(UIWindow*)window 
{ 
    NSUInteger count = window.subviews.count; 
    id v = [window.subviews objectAtIndex:count - 1]; 
    if (![@"UITransitionView" isEqual:NSStringFromClass([v class])]) return; 
    v = [window.subviews objectAtIndex:count - 2]; 
    if (![@"UIDimmingView" isEqual:NSStringFromClass([v class])]) return; 

    UIView *front = [window.subviews lastObject]; 
    [window addSubview:self]; 
    [window bringSubviewToFront:front]; 
} 

- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event 
{ 
    [self removeFromSuperview]; 
    [target performSelector:selector withObject:self]; 
} 

@end 

Enfoque 2
El primer enfoque es preferido, ya que éste tiene una lógica adicional para cada evento táctil en la forma modal.

Agregue la vista transparente como vista frontal de la ventana. Los eventos táctiles dentro del marco de la vista modal se pasan a él, y aquellos fuera del marco descartan el formulario modal.

Antes de que aparezca, la jerarquía de vista modal tiene este aspecto. Cuando aparece, UIDropShadowView reemplaza UITransitionView en las subvistas de la ventana. El UILayoutContainerView

UIDropShadowView 
    UIImageView 
    UILayoutContainerView 
     UINavigationTransitionView 
      UIViewControllerWrapperView 
       UIView (the modal view) 
     UINavigationBar 

La aplicación es en su mayoría los mismos que antes, con una nueva propiedad y addToWindow: reemplazado por addToWindow:modalView:.

Descartar Vista todavía se puede agregar a la ventana en viewWillAppear:, ya que el UIDropShadowView reemplaza el UITransitionView.

De nuevo, silenciosamente no hacemos nada si la jerarquía de vistas no es la esperada.

@property (nonatomic, retain) UIView *view; 

- (void) addToWindow:(UIWindow*)window modalView:(UIView*)v 
{ 
    while (![@"UILayoutContainerView" isEqual:NSStringFromClass([v class])]) { 
     v = v.superview; 
     if (!v) { 
      return; 
     } 
    } 

    self.view = v; 
    [window addSubview:self]; 
} 

- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event 
{ 
    CGPoint p = [self convertPoint:point toView:view]; 
    UIView *v = [view hitTest:p withEvent:event]; 

    return v ? v : [super hitTest:point withEvent:event]; 
} 
+0

¡esto sigue funcionando muy bien en iOS 6! – cscott530

+0

iOS 7 también .. – Mazyod

-4

creo que la respuesta correcta es "no hagas eso"

Cuestiones relacionadas