Как закрыть стек контроллеров модального представления с анимацией, не мигая на экране ни одним из представленных VC между верхним и нижним?

ОБНОВЛЕНО: исправлено с помощью описанного ниже метода «скриншот». Это работает, но есть ли более элегантный способ?

Как я могу закрыть стек контроллеров модального представления с анимацией, не высвечивая на экране какой-либо из представленных VC между верхним и нижним? Попытка сделать это с анимацией не работает. См. код ниже и встроенные комментарии, описывающие мою проблему. Вы можете скопировать/вставить этот код в новый проект в Xcode, чтобы убедиться в этом самостоятельно, если хотите!

//
//  ViewController.m
//  MultipleModals
//

#import "ViewController.h"
#import "MyViewController.h"
#import "MyHelper.h"

@interface ViewController ()

@end

@implementation ViewController

static BOOL doAgain = YES; // So when red appears again, we don't endlessly cycle (for testing)
- (void)viewDidAppear:(BOOL)animated
{
    // Invoke super
    [super viewDidAppear:animated];

    // Prevent loop when we dismiss all the way back to red (for testing)
    if (doAgain)
    {
        // Okay here's where the demo code starts...

        // PRESENTING a full stack of modals WITHOUT animation WORKS and results in the user
        // only seeing orange when this red view controller "appears" (red never actually appears, which is great)...

        MyViewController *purple = [[MyViewController alloc] init];
        purple.title = @"purple"; // For use in MyViewController's dealloc method
        purple.view.backgroundColor = [UIColor purpleColor];
        [self presentViewController:purple animated:NO completion:^{ // Purple successfully gets presented and the user never sees purple, great.
            NSLog(@"Purple?");
            MyViewController *green = [[MyViewController alloc] init];
            green.view.backgroundColor = [UIColor greenColor];
            green.title = @"green"; // For use in MyViewController's dealloc method
            [purple presentViewController:green animated:NO completion:^{ // Green successfully gets presented and the user never sees green, great.
                NSLog(@"Green?");
                MyViewController *orange = [[MyViewController alloc] init];
                orange.view.backgroundColor = [UIColor orangeColor];
                orange.title = @"orange"; // For use in MyViewController's dealloc method
                [green presentViewController:orange animated:NO completion:^{ // Orange successfully gets presented and the user DOES see orange, great.
                    NSLog(@"Orange?");

                    // FIXED MY ISSUE STARTING HERE

                    // Comment out the following code to toggle between
                    // the "flashing purple issue" and "the desired outcome" (single
                    // animation from top to bottom regardless of how many VCs are
                    // on the stack, i.e. no flashing).

                    // Get orange screenshot
                    UIImage *orangeScreenShotImage = [MyHelper screenshot];
                    UIImageView *orangeScreenShotImageView = [[UIImageView alloc] initWithImage:orangeScreenShotImage];

                    // Give purple an orange screenshot since orange will just "flash away" and then purple will animate
                    // away but we'll disguise purple to appear as if it's orange by layering a screenshot of orange on purple. Boom.
                    [purple.view addSubview:orangeScreenShotImageView];

                    // FIXED MY ISSUE ENDING HERE

                    // FOR TESTING PURPOSES... dismiss after 5 seconds...
                    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                        doAgain = NO; // Prevent viewDidAppear loop (related to my testing code)...

                        // THIS IS MY BUG HERE. WHEN I WANT TO **ANIMATE** THE DISMISSAL OF ORANGE ALL THE WAY BACK TO RED, HOWEVER, I SEE PURPLE FOR A FLASH BEFORE RED!! WHY?

                        // If I do not animate, things work as expected and I go from orange directly back to red in one flash. Why can't I go from orange back red WITH ANIMATION without seeing a flash of purple?
                        BOOL animateDismissalOfOrangeBackToRed = YES; // YES causes me to see a flash of purple before red, why?
                        [self dismissViewControllerAnimated:animateDismissalOfOrangeBackToRed completion:^{
                            NSLog(@"Back to red...");
                        }];
                    });
                }];
            }];
        }];
    }
}

- (void)viewDidLoad
{
    // Invoke super
    [super viewDidLoad];

    // Set self's background color
    self.view.backgroundColor = [UIColor redColor]; // Color of self, root VC
}

@end

MyViewController.m (позволяет нам использовать настраиваемый метод Dealloc для отладки)

//
//  MyViewController.m
//  MultipleModals
//

#import "MyViewController.h"

@interface MyViewController ()

@end

@implementation MyViewController

- (void)dealloc
{
    NSLog(@"Inside dealloc self.title = %@", self.title);
}

@end

ОБНОВЛЕНО: добавлен новый файл MyViewController.m для отладки расцепления.

Интересно, что лог выглядит так:

2014-11-20 10:06:28.847 MultipleModals[5470:946774] Purple?
2014-11-20 10:06:28.851 MultipleModals[5470:946774] Green?
2014-11-20 10:06:28.853 MultipleModals[5470:946774] Orange?
2014-11-20 10:07:04.055 MultipleModals[5470:946774] Inside dealloc self.title = orange
2014-11-20 10:07:04.056 MultipleModals[5470:946774] Inside dealloc self.title = green
2014-11-20 10:07:04.565 MultipleModals[5470:946774] Back to red...
2014-11-20 10:07:04.566 MultipleModals[5470:946774] Inside dealloc self.title = purple

ОБНОВЛЕНО: я добавил пример проекта, чтобы вы могли легко увидеть этот первый дескриптор, если хотите: https://github.com/johnerck/MultipleModals

Кроме того, я прочитал Представление Контроллеры представления из других контроллеров представления много раз. Они даже говорят: «Например, если пользователь отменяет текущую операцию, вы можете удалить все объекты в цепочке, отклонив первый представленный контроллер представления. Отказ от контроллера представления отклоняет не только этот контроллер представления, но и любые представленные им контроллеры представления. " Я вижу это поведение, но анимация отображает всего 3 представления, а не ожидаемые 2.


person John Erck    schedule 20.11.2014    source источник


Ответы (1)


Это не ошибка. Вы меняете анимацию удаления только для self.presentedViewController("фиолетовый") при dismissViewControllerAnimated, но не для всех вложенных VC. Когда "фиолетовый" получает сообщение об удалении с анимацией, он удаляет все presentedViewController без анимации. А то вы видите анимацию "фиолетового" без вложенных контроллеров. Чтобы проверить это, вы можете просто создать свой собственный класс VC и проверить метод -dealloc.

person kabarga    schedule 20.11.2014
comment
Есть ли какой-либо метод для достижения моей цели по отклонению всего стека, от верхнего модального до нижнего модального, все с одной анимацией отклонения, визуализирующей уход верха и раскрытие дна (не визуализируя какой-либо из VC между) ? - person John Erck; 20.11.2014
comment
Я добавил отладочные вызовы Dealloc, как вы предложили, и разместил пример проекта. Знаете ли вы какой-либо способ анимировать непосредственно сверху вниз в одной анимации, как если бы верхняя и нижняя VC в модальном стеке были единственными VC в модальном стеке. @кабарга - person John Erck; 20.11.2014
comment
Я думаю, что нет никакого способа сделать то, что вы хотите, основываясь на моем ответе. Я попытался отклонить их рекурсивно, но это не сработало. Такое ощущение, что стек модальных контроллеров — не лучшая иерархия в iOS для ваших целей. - person kabarga; 22.11.2014
comment
Я точно знаю! Как еще можно представить стек VC, которые пользователь может отклонять по одному, а также иметь возможность перемещаться в корень с помощью одной анимации? По сути, мы пытаемся сделать то же самое, что и метод popToRootViewControllerAnimated: UINavigationController, но с модально представленными VC, а не с навигационным контроллером... Кажется настолько странным, что это невозможно без моего скриншота выше, но я тоже в тупике. - person John Erck; 23.11.2014