Правильный способ отображения последовательных модальных представлений
-
30-09-2019 - |
Вопрос
У меня есть два представления, которые нужно показать модально, одно за другим.Это не сработает, если мы закроем и покажем последовательно, вот так:
[rootController dismissModalViewControllerAnimated: YES];
[rootController presentModalViewController: psvc animated: YES];
Второе модальное представление просто не отображается.
Я видел исправление, которое было примерно таким:
[rootController dismissModalViewControllerAnimated: YES];
[[UIApplication sharedApplication] beginIgnoringInteractionEvents];
[self performSelector: @selector(seekModal) withObject: nil afterDelay: 0.5];
[[UIApplication sharedApplication] endIgnoringInteractionEvents];
Проблема в том, что это не будет работать все время (иногда необходимая задержка больше).
Еще одним возможным решением может быть удаление анимации:
[rootController dismissModalViewControllerAnimated: NO];
[rootController presentModalViewController: psvc animated: YES];
Но мне бы очень хотелось сохранить анимацию, чтобы было ощущение, что первое модальное окно не мешает.Какие-либо предложения?
Решение
РЕДАКТИРОВАТЬ: «Правильный» механизм для этого в iOS5+ — использовать – dismissViewControllerAnimated:completion:
метод и представить контроллер последовательного представления из блока завершения.
Контроллер представления, отображаемый модально, будет иметь viewDidDisappear:animated:метод, вызываемый после завершения модальной анимации увольнения.AFIK, это единственное место, куда вы можете подключиться, чтобы инициировать последующий PresentModalViewController:animated:вызов.
У меня есть класс, который я использую для представления контроллеров модального представления, и он реализует логику, которую вы ищете, посредством обратного вызова к представляющему контроллеру представления после завершения закрытия.Чтобы использовать этот класс, просто выделите/инициализируйте экземпляр и представьте его с помощью обычного PresentViewController:animated:вызов.Реализуйте следующий метод в контроллере представления представления:
- (void) modalViewControllerDidDismiss:(UIViewController *)modalViewController
Это будет вызвано сразу же после того, как контроллер модального представления исчезнет, и в это время вы сможете представить новый контроллер модального представления.
Еще одна приятная вещь: поскольку этот класс является специализацией UINavigationController, вы можете настроить включение/выключение навигационной панели по своему усмотрению.Класс также имеет встроенную логику для отображения кнопки закрытия по вашему желанию.
Вот определение класса:
@protocol TSModalViewControllerDelegate
- (void) modalViewControllerDidDismiss: (UIViewController*) modalViewController;
@end
@interface TSModalViewController : UINavigationController
{
UIViewController* _originalParentViewController;
}
@property BOOL dismissButtonHidden;
- (id) initWithViewController: (UIViewController*) vc;
- (id) initWithClass: (Class) c;
- (id) initWithClass: (Class) c nibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil;
@end
И реализация класса:
@implementation TSModalViewController
@synthesize dismissButtonHidden;
- (id) initWithViewController: (UIViewController *)vc
{
return [super initWithRootViewController: vc];
}
- (id) initWithClass:(Class)c
{
UIViewController* vc = [[[c alloc] init] autorelease];
return [self initWithViewController: vc];
}
- (id) initWithClass: (Class) c nibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
UIViewController* vc = [[[c alloc] initWithNibName:nibNameOrNil bundle:nibBundleOrNil] autorelease];
return [self initWithViewController: vc];
}
- (void) viewDidAppear: (BOOL) animated
{
[super viewDidAppear: animated];
[_originalParentViewController release];
_originalParentViewController = [self.parentViewController retain];
if (!self.dismissButtonHidden)
{
UIBarButtonItem* dismissButton = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemStop
target: self
action: @selector(onDismiss:)] autorelease];
UIViewController* rootViewController = [self.viewControllers objectAtIndex:0];
rootViewController.navigationItem.leftBarButtonItem = dismissButton;
self.navigationBarHidden = NO;
}
}
- (void) viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear: animated];
if ( [_originalParentViewController respondsToSelector: @selector(modalViewControllerDidDismiss:)] )
{
[_originalParentViewController performSelector: @selector(modalViewControllerDidDismiss:) withObject: self];
}
}
- (void) dismissModalViewControllerAnimated:(BOOL)animated
{
return [self.parentViewController dismissModalViewControllerAnimated: animated];
}
- (void) onDismiss: (id) sender
{
[self.parentViewController dismissModalViewControllerAnimated: YES];
}
- (void) didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (void) viewDidUnload
{
[super viewDidUnload];
}
- (void)dealloc
{
[_originalParentViewController release];
[super dealloc];
}
@end
и вот как вы можете его использовать (в контексте какого-нибудь обычного контроллера представления):
- (void) onShowIt:(id)sender
{
TSModalViewController* mvc = [[[TSModalViewController alloc] initWithClass: [MyModalViewController class] nibName: @"MyModalViewController" bundle:nil] autorelease];
mvc.dismissButtonHidden = YES; // set to no if you don't want an "automatic" close button
[self presentModalViewController: mvc animated: YES];
}
а вот метод обратного вызова увольнения, который представляет новый контроллер модального представления:
- (void) modalViewControllerDidDismiss:(UIViewController *)modalViewController
{
MyModalViewController* vc = [[[MyModalViewController alloc] initWithNibName: @"MyModalViewController" bundle:nil] autorelease];
vc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
TSModalViewController* mvc = [[[TSModalViewController alloc] initWithViewController: vc] autorelease];
[self presentModalViewController: mvc animated: YES];
}
Другие советы
rootController может сказать, когда последний из контроллеров модальных просмотра сверху исчез, потому что он получит ViewDiDAppear:. Вы пытались связать нынешнегоModalViewController: последующего контроллера представления для этого?
Если вы действительно хотите объединить в цепочку с несколькими видом на анимацию, я бы на самом деле предложил просто обращаться с логикой анимации самостоятельно. Это не слишком сложно, и тогда вы можете иметь тонкозернистый контроль над тем, как представлены мнения. Я только что записал что-то похожее на другой вопрос здесь:
iOS - Как вы управляете размером модального контроллера просмотра?
Вы можете просто анимировать вид на просмотр, анимируйте вид на вид, и когда ваш селектор AnimationDidStop называется, анимировал второй вид. Приятная часть этого заключается в том, что вы также можете играть с видом на непрозрачность и направление анимации, а также решать именно, когда представления должны появиться. Например, вы можете иметь второе представление на скольжении по сравнению с первым представлением, поскольку первый вид скользят; Не нужно ждать первого, чтобы завершить свою анимацию.
Ваша проблема связана с «Показать модальный вид внутри модального представления»? Я публикую ответ об этом здесь:Вид на iPhone Modal внутри другого модального представления?
Лучшее решение, которое я нашел для чего-то вроде этого (если все они являются равными детьми родительского вида) - это исправлять свои взгляды на UiscrollView с включенным подкатом, (вы можете добавить элемент управления страницей внизу, чтобы сделать его понятно, а для навигации ) Затем добавьте вид на контроллеры на просмотр страницы, когда они приходят на экране, удалите, как они выходят на экран.
Возможно, вы также должны быть пустыми звонком -ViewWillAppear и -viewWilldisAppear, если контроллеры полагаются на это называется. Это кажется вроде Hack-Ish, когда вы кодируете все это, но, как только у вас его работают, он выглядит гладким и естественным, и нет никакого ожидания, связанного с анимированием одним видом, а затем анимирует следующий один раз ушел.
Я нахожу с помощью Modal View's -viewdiddissapear, чтобы вызвать методы на представлением режиме просмотра работы очень хорошо. Одним из преимуществ является возможность задержать делиток на модальном контроллере представления. Пожалуйста, опубликуйте любые улучшения, которые я могу сделать. Мое вдохновение для создания этого протокола приехала из IOS 5 'EmavissviewControllerAnimated: завершение: «Дополнение к UiviewController. Я хотел эту функциональность в iOS 4.3.
Underdelegautprotocol.h.
@protocol PresentorDelegateProtocol <NSObject>
@optional
/*
Extra protocol methods defined in protocol for flexibility.
Main methods are:
- (void)dismissPresentingModalViewController:(id)modalView animated:(BOOL)animated;
- (void)modalViewDissapeared:(id)modalView; //used in modal view's -viewDidDissapear
*/
- (void)dismissPresentingModalViewController:(id)modalView animated:(BOOL)animated;
- (void)modalViewDissapeared:(id)modalView;
// use the block in this method send messages to save state, etc. This is the one I like to use.
- (void)dismissPresentingModalViewController:(id)modalView animated:(BOOL)animated withBlock:(void(^)())block;
// use in other classes that are not controlling dismissal of the modal view
- (void)executeBlockOnModalDissapearance: (void(^)())block;
@end
Resentingviewcontroller.h.
#import "PresentorDelegateProtocol.h"
@interface PresentingViewController : UIViewController <PresentorDelegateProtocol>
- (void)showModalVC;
@end
Modalviewcontroller.h.
#import "PresentorDelegateProtocol.h"
@interface ModalViewController : UIViewController
@property (nonatomic, assign) id <PresentorDelegateProtocol> presentorDelegate;
- (void)close;
@end
Resentingviewcontroller.m.
#import "PresentingViewController.h"
#import "ModalViewController.h"
@implementation PresentingModalViewController
- (void)showModalVC
{
ModalViewController *modalVC = [[ModalViewController alloc] initWithNibName:@"ModalViewController" bundle:nil];
modalVC.presentorDelegate = self;
[self presentModalViewController:modalVC animated:YES];
}
- (void)dismissPresentingModalViewController:(id)modalView animated:(BOOL)animated
{
if ([modalView isKindOfClass:[ModalViewController class]]) {
NSLog(@"Can invoke based on class");
}
[self dismissModalViewControllerAnimated:animated];
}
- (void)dismissPresentingModalViewController:(id)modalView animated:(BOOL)animated withBlock:(void(^)())block
{
block();
/* execute block before or after calling to dismiss modal view */
[self dismissPresentingModalViewController:modalView animated:animated];
//block();
}
- (void)modalViewDissapeared:(id)modalView
{
if ([modalView isKindOfClass:[ModalViewController class]]) {
NSLog(@"Do stuff based on class.");
}
}
- (void)executeBlockOnModalDissapearance: (void(^)())block
{
block();
NSLog(@"This delay's dealloc on modal view until block completes");
}
@end
Modalviewcontroller.m.
#import "ModalViewController.h"
@implementation ModalViewController
@synthesize presentorDelegate;
- (void)close
{
if (1 == 0 /*need to do something before dealloc*/){
[self.presentorDelegate dismissPresentingModalViewController:self animated:YES withBlock:^{
NSLog(@"Do stuff with block. Save, animate, etc");
}];
} else {
[self.presentorDelegate dismissPresentingModalViewController:self animated:YES];
}
}
- (void)viewDidDisappear:(BOOL)animated
{
if (1 == 0 /*stuff to do*/){
[self.presentorDelegate executeBlockOnModalDissapearance:^{
// do stuff before modal view is deallocated
}];
}
[self.presentorDelegate modalViewDissapeared:self];
presentorDelegate = nil;
[super viewDidDisappear:animated];
}
@end;
// present modal view inside another presented modal view
FirstViewController *firstVC = [[FirstViewController alloc] initWithNibName:@"FirstViewController" bundle:nil];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController: firstVC];
// Note: you can use your viewcontroller instead self.window.rootViewController
[self.window.rootViewController presentViewController:navController animated:YES completion:^{
//code...
SecondViewController *secondVC = [[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:nil];
[navController presentViewController: secondVC animated:YES completion:nil];
}
}];