当在表单外发生触摸时,如何关闭呈现为“表单”的模态视图控制器?

时间:2011-02-09 15:15:38

标签: cocoa-touch ipad uiviewcontroller

我有一个以表单样式呈现的视图控制器(带有UIWebView)。 我必须在视图控制器的视图的UIToolbar中放置一个“完成”按钮才能将其解除。 但是,由于以“表单”样式呈现它会在视图控制器的视图之外留下大量未使用的空间......我在游荡... 有没有办法检测视图外的触摸?在那个“变灰”的地方? 提前致谢

2 个答案:

答案 0 :(得分:18)

在iOS 4.2上,基于导航控制器的应用程序的视图层次结构与模态表单在viewWillAppear:期间如下所示。一旦出现模态视图,UITransitionView就被包含模态视图层次结构的UIDropShadowView所取代。

UIWindow
    UILayoutContainerView (regular hierarchy)
    UIDimmingView 
    UITransitionView

Apple警告不要依赖内置视图的子视图,因为这些视图被认为是私有的,并且可能在将来的版本中发生变化。这可能会破坏您的应用。

方法1
我们可以在窗口的最后两个子视图之间插入透明视图,并通过关闭模态窗体来响应触摸事件。

此实现检查窗口的视图层次结构是否符合预期,否则将默默地执行任何操作。

在模态视图控制器中从DismissingView创建并使用viewWillAppear:

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

并实施。

@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

方法2
第一种方法是首选方法,因为这种方法对模态形式的每个触摸事件都有额外的逻辑。

将透明视图添加为窗口的前视图。模态视图框架内的触摸事件将传递给它,框架外的触摸事件将忽略模态窗体。

在它出现之前,模态视图层次结构如下所示。当它出现时,UIDropShadowView将替换窗口子视图中的UITransitionView。 UILayoutContainerView

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

实施与以前大致相同,新属性addToWindow:替换为addToWindow:modalView:

由于UIDropShadowView取代了UITransitionView,因此仍然可以将{[1}}中的DismissingView添加到窗口中。

如果视图层次结构不符合预期,我们也会默默地做任何事情。

viewWillAppear:

答案 1 :(得分:-4)

我认为正确的答案是,"不要这样做"