Подтвердить что ты не робот

Сбросить сразу несколько диспетчеров модального просмотра?

Итак, у вас есть стек с тремя контроллерами представлений, где A - корень, B - первый контроллер модального представления, а C - третий модальный vc. Я хотел бы перейти от С к А сразу. Я пробовал это решение для отклонения. Это работает, но не правильно. То есть, когда последний контроллер представления отклонен, он будет кратковременно показывать второй контроллер представления до того, как будет показан первый. То, что я ищу, - это способ получить от третьего vc к первому в одной приятной анимации, не заметив второго представления. Любая помощь по этому поводу очень известна.

4b9b3361

Ответ 1

Убедитесь, что вы только вызываете dismissModalViewControllerAnimated: один раз.

Я обнаружил, что запрос отклонить каждый сложный контроллер модального представления заставит оба их оживить.

У вас есть: A =modal> B =modal> C

Вы должны вызывать только [myViewControllerA dismissModalViewControllerAnimated:YES]

Если вы используете [myViewControllerB dismissModalViewControllerAnimated:YES], он отклонит C, а не B. В обычном (нераспакованном) использовании он отклонит B (из-за того, что цепочка ответчиков, пузырящая сообщение до A). В сложном сценарии, который вы описываете B, является контроллером родительского представления, и это имеет приоритет перед тем, чтобы быть модульным контроллером представления.

Ответ 2

Несмотря на то, что принятый ответ действительно сработал у меня, он может быть устаревшим сейчас и оставил странную анимацию, где самый верхний модал немедленно исчезнет, ​​и анимация будет на задней части модального просмотра. Я пробовал много вещей, чтобы избежать этого, и в итоге мне пришлось немного взломать, чтобы он выглядел красиво. Примечание: (проверено только в iOS8 +, но должно работать iOS7 +)

В принципе, viewControllerA создает UINavigationController с viewControllerB в качестве корневого представления и представляет его модально.

// ViewControllerA.m
- (void)presentViewB {
    ViewControllerB *viewControllerB = [[ViewControllerB alloc] init];
    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewControllerB];

    navigationController.modalPresentationStyle = UIModalPresentationFormSheet;
    [self presentViewController:navigationController animated:YES completion:nil];
}

Теперь в viewControllerB мы представим viewControllerC таким же образом, но после его представления мы собираемся сделать снимок viewControllerC над уровнем представления на контроллере навигации viewControllerB. Затем, когда viewControllerC исчезает во время увольнения, мы не увидим изменения, и анимация будет выглядеть красивой.

//ViewControllerB.m
- (void)presentViewC {
    ViewControllerC *viewControllerC = [[ViewControllerC alloc] init];

    // Custom presenter method to handle setting up dismiss and snapshotting 
    // I use this in a menu that can present many VC so I centralized this part.
    [self presentViewControllerForModalDismissal:viewControllerC];
}

Ниже приведены мои вспомогательные функции, которые используются для представления представления и обработки увольнения. Одно замечание: я использую Purelayout для добавления ограничений автоматического компоновки. Вы можете изменить это, чтобы добавить их вручную или получить Purelayout на https://github.com/PureLayout/PureLayout

#pragma mark - Modal Presentation Helper functions
- (void)presentViewControllerForModalDismissal:(UIViewController*)viewControllerToPresent {
    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewControllerToPresent];
    navigationController.modalPresentationStyle = UIModalPresentationFormSheet;

    // Ensure that anything we are trying to present with this method has a dismissBlock since I don't want to force everything to inherit from some base class. 
    NSAssert([viewControllerToPresent respondsToSelector:NSSelectorFromString(@"dismissBlock")], @"ViewControllers presented through this function must have a dismissBlock property of type (void)(^)()");
    [viewControllerToPresent setValue:[self getDismissalBlock] forKey:@"dismissBlock"];

    [self presentViewController:navigationController animated:YES completion:^{
        // We want the presented view and this modal menu to dismiss simultaneous. The animation looks weird and immediately becomes the menu again when dismissing.
        // So we are snapshotting the presented view and adding it as a subview so you won't see the menu again when dismissing.
        UIView *snapshot = [navigationController.view snapshotViewAfterScreenUpdates:NO];
        [self.navigationController.view addSubview:snapshot];
        [snapshot autoPinEdgesToSuperviewEdges];
    }];
}

- (void(^)()) getDismissalBlock {
    __weak __typeof(self) weakSelf = self;
    void(^dismissBlock)() = ^{
        __typeof(self) blockSafeSelf = weakSelf;
        [blockSafeSelf.navigationController.presentingViewController dismissViewControllerAnimated:YES completion:nil];
    };

    return dismissBlock;
}

Теперь нам просто нужно убедиться, что у нас есть функция throwBlock, определенная как свойство в ViewControllerC.h(вы можете, очевидно, заменить эту целую часть на методы делегирования или другие одинаково захватывающие шаблоны проектирования, важная часть состоит в том, чтобы обрабатывать увольнение на viewControllerB уровень)

// ViewControllerC.h
@interface ViewControllerC : UIViewController
@property (nonatomic, copy) void (^dismissBlock)(void);
@end

//ViewControllerC.m
// Make an method to handle dismissal that is called by button press or whatever logic makes sense.
- (void)closeButtonPressed {
    if (_dismissBlock)  {// If the dismissblock property was set, let the block handle dismissing
        _dismissBlock();
        return;
    }

    // Leaving this here simply allows the viewController to be presented modally as the base as well or allow the presenter to handle it with a block.
    [self dismissViewControllerAnimated:YES completion:nil];
}

Надеюсь, это поможет, счастливое программирование:)

Ответ 3

Вы можете отклонить эти modalViewControllers в своем корневом контролере.

    UIViewController *viewController = yourRootViewController;

    NSMutableArray *array = [NSMutableArray array];
    while (viewController.modalViewController) {
        [array addObject:viewController];
        viewController = viewController.modalViewController;
    }

    for (int i = 0; i < array.count; i++) {
        UIViewController *viewController = array[array.count-1-i];
        [viewController dismissModalViewControllerAnimated:NO];
    }

Ответ 4

Что вы хотите использовать? popToRootViewControllerAnimated:. Он доставит вас к корневому контроллеру, не показывая все промежуточные.