2011-02-09 9 views
20

Mam kontroler widoku (z interfejsem UIWebView) prezentuję w stylu arkusza formularza. Muszę umieścić przycisk "Gotowe" w pasku UIToolbar widoku w Kontroli widoku, aby go zwolnić. Ale, ponieważ prezentowanie go w stylu "Formularza arkusza" pozostawia mnóstwo niewykorzystanej przestrzeni poza widokiem kontrolera widoku ... Błąkałem się. Czy istnieje sposób wykrywania dotyku poza widokiem? w tym "wyszarzonym" obszarze? Z góry z góryJak odrzucić kontroler widoku modalnego przedstawiony jako "Arkusz formularzy", gdy dotknięcie pojawi się poza arkuszem formularza?

+1

znacznie prostsze rozwiązanie tutaj: http: // stackoverflow.com/questions/2623417/iphone-sdk-dismissing-modal-viewcontrollers-on-ipad-by-click-outside-of-it – onekiloparsec

+0

@ Cédric To rozwiązanie nie jest wystarczająco dobre dla naszego przypadku użycia. Dodaj popover, który wykracza poza granice widoku i bam. To rozwiązanie pęka. – Mazyod

Odpowiedz

18

Na iOS 4.2 hierarchia widoku aplikacji opartej na kontrolerze nawigacyjnym z formularzem modalnym jest następująca podczas viewWillAppear:. Gdy pojawi się widok modalny, UITransitionView został zastąpiony przez UIDropShadowView, który zawiera modalną hierarchię widoków.

UIWindow 
    UILayoutContainerView (regular hierarchy) 
    UIDimmingView 
    UITransitionView 

Jabłko ostrzegają przed powołując się na subviews wbudowanych w widokach, jak są one traktowane jako prywatne i mogą ulec zmianie w przyszłych wydaniach. Może to potencjalnie uszkodzić twoją aplikację.

Approach 1
Możemy wstawić przejrzystego widoku pomiędzy dwoma ostatnimi subviews z okna, a nie reagować na dotyk zdarzenia oddalając formularz modalne.

Implementacja ta sprawdza, czy hierarchia widoków okna jest zgodna z oczekiwaniami, i jeśli nic nie robi, nic nie robi.

Tworzenie i używanie DismissingView z viewWillAppear: w modalne kontrolera widoku.

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

I wdrożenie. Korzystne jest

@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 

Sposób 2
W pierwszym podejściu, ten ma dodatkową logikę każdym przypadku dotykowego w postaci modalnej.

Dodaj przezroczysty widok jako widok z przodu okna. Zdarzenia dotykowe w ramie widoku modalnego są przekazywane do niego, a te znajdujące się poza ramką odrzucają formę modalną.

Zanim się pojawi, hierarchia widoku modalnego wygląda następująco. Kiedy się pojawi, UIDropShadowView zastępuje UITransitionView w pod-widokach okna. UILayoutContainerView

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

Realizacja jest w większości takie same jak poprzednio, z nowym własności i addToWindow: zastąpiona addToWindow:modalView:.

DismissingView można jeszcze dodać do okna w viewWillAppear:, ponieważ UIDropShadowView zastępuje UITransitionView.

Znów nic nie robimy, jeśli hierarchia widoków nie jest zgodna z oczekiwaniami.

@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

to nadal działa świetnie w iOS 6! – cscott530

+0

iOS 7 również .. – Mazyod

-4

myślę, że prawidłowa odpowiedź brzmi: "nie rób tego"

Powiązane problemy