Cocoa touch 如何取消显示为“的模态视图控制器”;表格「;当触摸发生在表单外时?

Cocoa touch 如何取消显示为“的模态视图控制器”;表格「;当触摸发生在表单外时?,cocoa-touch,ipad,uiviewcontroller,Cocoa Touch,Ipad,Uiviewcontroller,我有一个视图控制器(带有UIWebView),我以表单样式呈现。 我必须在视图控制器中视图的UIToolbar中放置一个“完成”按钮,才能将其解除。 但是,由于以“表单表”样式呈现,在视图控制器的视图之外留下了大量未使用的空间。。。我在流浪。。 有没有办法检测视野之外的触摸?在那个“灰色”区域? 提前感谢iOS 4.2上的,带有模式表单的基于导航控制器的应用程序的视图层次结构如下:视图将出现:。模态视图出现后,UITransitionView将被包含模态视图层次结构的UIDropShadowVi

我有一个视图控制器(带有UIWebView),我以表单样式呈现。 我必须在视图控制器中视图的UIToolbar中放置一个“完成”按钮,才能将其解除。 但是,由于以“表单表”样式呈现,在视图控制器的视图之外留下了大量未使用的空间。。。我在流浪。。 有没有办法检测视野之外的触摸?在那个“灰色”区域?
提前感谢iOS 4.2上的,带有模式表单的基于导航控制器的应用程序的视图层次结构如下:
视图将出现:
。模态视图出现后,UITransitionView将被包含模态视图层次结构的UIDropShadowView替换

UIWindow
    UILayoutContainerView (regular hierarchy)
    UIDimmingView 
    UITransitionView
苹果警告不要依赖内置视图的子视图,因为这些子视图被认为是私有的,在未来的版本中可能会改变。这可能会破坏你的应用程序

方法1
我们可以在窗口的最后两个子视图之间插入一个透明视图,并让它通过忽略模态形式来响应触摸事件

此实现检查窗口的视图层次结构是否符合预期,如果不符合预期,则不会执行任何操作

view创建并使用
DismissingView
将出现在模态视图控制器中:

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:

DismissingView仍然可以添加到
视图中的窗口将出现:
,因为UIDropShadowView替换了UITransitionView

同样,如果视图层次结构不符合预期,我们将不执行任何操作

@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];
}

我认为正确的答案是,“不要那样做”

这里更简单的解决方案:@Cédric该解决方案对于我们的用例来说不够好。添加一个超出视图边界的弹出框,然后单击bam。这个解决方案失败了。