В 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:
.
DismissingView все еще можно добавить в окно в viewWillAppear:
, поскольку 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];
}