У меня есть View Controller (с UIWebView), который я представляю в стиле листа. Я должен поместить кнопку "Готово" в UIToolbar представления в контроллере просмотра, чтобы он был отклонен. Но, поскольку представление его в стиле "Лист форм" оставляет много неиспользуемого пространства вне представления View Controller... Я блуждал.. Есть ли способ обнаружить прикосновение вне представления? в этой "серой" области? Спасибо заранее
Как отклонить контроллер модального представления, представленный как "Лист формы", когда прикосновение происходит за пределами листа формы?
Ответ 1
В 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 в окнах subviews. 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];
}
Ответ 2
Я думаю, что правильный ответ: "не делай этого"