2011-02-09 9 views
20

Ho un controller di visualizzazione (con UIWebView) presente nello stile del foglio di forma. Devo mettere un pulsante "Fine" nella barra degli strumenti UIT della vista nel controller di visualizzazione per farlo scartare. Ma, dal momento che presentarlo nello stile "Modulo" lascia un sacco di spazio inutilizzato al di fuori della vista del View Controller ... Stavo vagando .. C'è un modo per rilevare un tocco al di fuori della vista? in quella zona "ombreggiata"? Grazie in anticipocome ignorare un controller di visualizzazione modale presentato come "Foglio modulo" quando un tocco si verifica all'esterno del foglio modulo?

+1

soluzione molto più semplice qui: http: // StackOverflow.it/questions/2623417/iphone-sdk-dismissing-modal-viewcontrollers-on-ipad-by-click-outside-of-it – onekiloparsec

+0

@ Cédric Questa soluzione non è abbastanza buona per il nostro caso d'uso. Aggiungi un popover che si estende oltre i limiti della vista e bam. Questa soluzione si rompe. – Mazyod

risposta

18

Su iOS 4.2, la gerarchia di viste di un'app basata sul controller di navigazione con un foglio di modulo modale è la seguente durante viewWillAppear:. Una volta visualizzata la vista modale, UITransitionView è stato sostituito da UIDropShadowView che contiene la gerarchia della vista modale.

UIWindow 
    UILayoutContainerView (regular hierarchy) 
    UIDimmingView 
    UITransitionView 

di Apple avvisate contro basandosi sulle subviews di costruito in vista, in quanto questi sono considerati privati ​​e possono cambiare nelle versioni future. Questo potrebbe potenzialmente rompere la tua app.

Approccio 1
Possiamo inserire una visione trasparente tra le ultime due subviews di finestra, e lo hanno rispondere a toccare gli eventi respingendo il modulo modale.

Questa implementazione controlla che la gerarchia della vista della finestra sia come previsto e silenziosamente non farà nulla se non.

Creare e utilizzare DismissingView da viewWillAppear: nel controller della vista modale.

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

E l'implementazione.

@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 

Approccio 2
Il primo approccio è preferito, poiché questo ha logica aggiuntiva per ogni evento tocco sul modulo modale.

Aggiungere la vista trasparente come vista frontale della finestra. Gli eventi di tocco all'interno del frame della vista modale vengono passati ad esso, mentre quelli esterni al riquadro ignorano il modulo modale.

Prima che compaia, la gerarchia della vista modale appare così. Quando appare, UIDropShadowView sostituisce UITransitionView nelle sottoview della finestra. L'UILayoutContainerView

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

L'implementazione è quasi lo stesso di prima, con una nuova proprietà e addToWindow: sostituito da addToWindow:modalView:.

DismissingView può ancora essere aggiunto alla finestra in viewWillAppear:, poiché UIDropShadowView sostituisce UITransitionView.

Ancora una volta non facciamo nulla se la gerarchia della vista non è come previsto.

@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

funziona ancora perfettamente in iOS 6! – cscott530

+0

iOS 7 e .. – Mazyod

-4

Penso che la risposta giusta è: "non farlo"

Problemi correlati