Изменение корня просматривает контроллер iOS Window

Обычно корневой контроллер представления iOS Window инициализирован однажды в начале к контроллеру панели вкладок или контроллеру навигации? Это должно хорошо изменить корневой контроллер представления многократно в рамках приложения?

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

62
задан 28 August 2016 в 19:07

5 ответов

Более обычно использовать "представленный контроллер представления" (presentViewController:animated:completion:). Вы можете иметь как многие из них как Вам угодно эффективно появляющихся перед (и в основном заменяющий) корневой контроллер представления. Не должно быть никакой анимации, если Вы не хотите, или может быть. Можно отклонить представленный контроллер представления для возвращения к исходному корневому контроллеру представления, но Вы не имеете к; представленный контроллер представления может просто быть там навсегда, если Вам нравится.

Вот раздел по представленным контроллерам представления из моей книги:

http://www.apeth.com/iOSBook/ch19.html#_presented_view_controller

В этой схеме (от ранее в той главе), представленный контроллер представления полностью принял интерфейс приложения; корневой контроллер представления и его подпредставления больше не находятся в интерфейсе. Корневой контроллер представления все еще существует, но это легко и не имеет значения.

enter image description here

47
ответ дан 31 October 2019 в 13:36

Из комментариев к сарже-k's отвечают, что я создал рабочее решение с обходным решением странного поведения, когда существует модальный контроллер представления, представленный по старому rootViewController:

extension UIView {
    func snapshot() -> UIImage {
        UIGraphicsBeginImageContextWithOptions(bounds.size, false, UIScreen.mainScreen().scale)
        drawViewHierarchyInRect(bounds, afterScreenUpdates: true)
        let result = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return result
    }
}

extension UIWindow {
    func replaceRootViewControllerWith(_ replacementController: UIViewController, animated: Bool, completion: (() -> Void)?) {
        let snapshotImageView = UIImageView(image: self.snapshot())
        self.addSubview(snapshotImageView)

        let dismissCompletion = { () -> Void in // dismiss all modal view controllers
            self.rootViewController = replacementController
            self.bringSubview(toFront: snapshotImageView)
            if animated {
                UIView.animate(withDuration: 0.4, animations: { () -> Void in
                    snapshotImageView.alpha = 0
                }, completion: { (success) -> Void in
                    snapshotImageView.removeFromSuperview()
                    completion?()
                })
            }
            else {
                snapshotImageView.removeFromSuperview()
                completion?()
            }
        }
        if self.rootViewController!.presentedViewController != nil {
            self.rootViewController!.dismiss(animated: false, completion: dismissCompletion)
        }
        else {
            dismissCompletion()
        }
    }
}

Для замены rootViewController просто используйте:

let newRootViewController = self.storyboard!.instantiateViewControllerWithIdentifier("BlackViewController")
UIApplication.sharedApplication().keyWindow!.replaceRootViewControllerWith(newRootViewController, animated: true, completion: nil)

Hope это помогает :) протестированный на iOS 8.4; также протестированный на поддержку контроллеров навигации (должен поддерживать также контроллеры панели вкладок и т.д., но я не протестировал ее)

Объяснение

, Если существует модальный контроллер представления, представленный по старому rootViewController, rootViewController заменяется, но старое представление все еще остается зависать ниже представления нового rootViewController (и будьте видны, например, во время Зеркально отраженной Горизонтали, или Перекрестный Расторгают анимации перехода), и старая иерархия контроллера представления остается выделенной (который может вызвать серьезные проблемы памяти, если замена происходит многократно).

, Таким образом, единственное решение состоит в том, чтобы отклонить все модальные контроллеры представления и затем заменить rootViewController. Снимок экрана помещается над окном во время увольнения и замены для сокрытия ужасного процесса высвечивания.

37
ответ дан 31 October 2019 в 13:36

Для iOS8 мы также должны установить ниже двух параметров на ДА.

providesPresentationContextTransitionStyle
definesPresentationContext

Вот мой код для представления прозрачного образцового контроллера представления под контроллером навигации для iOS 6 и выше.

ViewController *vcObj = [[ViewController alloc] initWithNibName:NSStringFromClass([ViewController class]) bundle:nil];
UINavigationController *navCon = [[UINavigationController alloc] initWithRootViewController:vcObj];

if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {

    navCon.providesPresentationContextTransitionStyle = YES;
    navCon.definesPresentationContext = YES;
    navCon.modalPresentationStyle = UIModalPresentationOverCurrentContext;

    [self presentViewController:navCon animated:NO completion:nil];
}
else {

    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    [self presentViewController:navCon animated:NO completion:^{
        [navCon dismissViewControllerAnimated:NO completion:^{
            appDelegate.window.rootViewController.modalPresentationStyle = UIModalPresentationCurrentContext;
            [self presentViewController:navCon animated:NO completion:nil];
            appDelegate.window.rootViewController.modalPresentationStyle = UIModalPresentationFullScreen;

        }];
    }];
}
3
ответ дан 31 October 2019 в 13:36

iOS 8.0, XCode 6.0.1, ARC включил

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

это хорошо, для изменения корневого контроллера представления многократно, в рамках приложения?

ответ да . Я должен был сделать это недавно для сброса моей иерархии UIView после начальных UIViews, которые были частью приложения. запуск больше не был необходим. Другими словами, можно сбросить "rootViewController" от любого другого UIViewController в любое время после приложения. "didFinishLoadingWithOptions".

, Чтобы сделать это...

1) Объявляют ссылку на Ваше приложение. делегат (приложение под названием "Тест")...

TestAppDelegate *testAppDelegate = (TestAppDelegate *)[UIApplication sharedApplication].delegate;

2) Выбор UIViewController Вы хотите сделать свой "rootViewController"; или от раскадровки или определяют программно...

    a) раскадровка (удостоверяются идентификатор, т.е. storyboardID, существует в Инспекторе Идентификационных данных для UIViewController):
UIStoryboard *mainStoryBoard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];

NewRootViewController *newRootViewController = [mainStoryBoard instantiateViewControllerWithIdentifier:@"NewRootViewController"];

    b) программно (мог addSubview, и т.д.)
UIViewController *newRootViewController = [[UIViewController alloc] init];
newRootViewController.view = [[UIView alloc] initWithFrame:CGRectMake(0, 50, 320, 430)];
newRootViewController.view.backgroundColor = [UIColor whiteColor];

3) Соединение всего этого...

 testAppDelegate.window.rootViewController = newRootViewController;
[testAppDelegate.window makeKeyAndVisible];

4) можно даже добавить анимацию...

testAppDelegate.window.rootViewController = newRootViewController;
    [testAppDelegate.window makeKeyAndVisible];

newRootViewController.view.alpha = 0.0;

    [UIView animateWithDuration:2.0 animations:^{

        newRootViewController.view.alpha = 1.0;

    }];

Hope это помогает кому-то! Аплодисменты.

корневой контроллер представления для окна.

корневой контроллер представления обеспечивает представление содержания окна. Присвоение контроллера представления к этому свойству (или программно или использование Интерфейсного Разработчика) устанавливают представление controller’s представление как представление содержания окна. Если окно имеет существующую иерархию представления, старые представления удалены, прежде чем новые установлены. Значение по умолчанию этого свойства является нолем.

*Update 9/2/2015

Как комментарии ниже указывает, необходимо обработать демонтаж старого контроллера представления, когда новый контроллер представления представлен. Можно выбрать иметь переходный контроллер представления, в котором Вы обработаете это. Вот несколько подсказок о том, как реализовать это:

[UIView transitionWithView:self.containerView
                  duration:0.50
                   options:options
                animations:^{

                    //Transition of the two views
                    [self.viewController.view removeFromSuperview];
                    [self.containerView addSubview:aViewController.view];

                }
                completion:^(BOOL finished){

                    //At completion set the new view controller.
                    self.viewController = aViewController;

                }];
50
ответ дан 31 October 2019 в 13:36

Можно изменить rootViewController окна всюду по жизненному циклу приложения.

UIViewController *viewController = [UIViewController alloc] init];
[self.window setRootViewController:viewController];

при изменении rootViewController все еще можно хотеть добавить UIImageView как подпредставление об окне для действия как изображение всплеска. Я надеюсь, что это имеет смысл, что-то вроде этого:

- (void) addSplash {
    CGRect rect = [UIScreen mainScreen].bounds;
    UIImageView *splashImage = [[UIImageView alloc] initWithFrame:rect];
    splashImage.image = [UIImage imageNamed:@"splash.png"];
    [self.window addSubview:splashImage];
}

- (void) removeSplash {
    for (UIView *view in self.window.subviews) {
      if ([view isKindOfClass:[UIImageView class]]) {
        [view removeFromSuperview];
      }
    }
}
5
ответ дан 31 October 2019 в 13:36

Другие вопросы по тегам:

Похожие вопросы: