Представление полупрозрачного диспетчера представлений, работающего как в iOS7, так и в iOS8

У меня был следующий код, который отлично работал в iOS7.

[UIView animateWithDuration:0.5 animations:^(void) {
    self.view.alpha = 0.5;
    [self.navigationController.navigationBar setAlpha:0.3];

}]; //to make the background view controller semi-transparent
UIViewController *rootViewController = [UIApplication sharedApplication].delegate.window.rootViewController;
[rootViewController setModalPresentationStyle:UIModalPresentationCurrentContext];
OverlayViewController *ctlr = [storyBoard instantiateViewControllerWithIdentifier:@"OverlayViewController"];
//present the OverlayViewController
[self presentViewController:ctlr animated:YES completion:nil];

Тогда у меня было следующее в viewWillAppear контроллера фонового представления, чтобы вернуть его представление в полный непрозрачный.

[UIView animateWithDuration:1.0 animations:^(void) {
    self.view.alpha = 1.0;
    [self.navigationController.view setAlpha:1.0];
}];

Теперь, с iOS8, приведенный выше код не устанавливает, чтобы фон был полупрозрачным. Черный цвет окружает OverlayViewController.

Я нашел онлайн, что использование UIModalPresentationOverCurrentContext даст ожидаемое поведение. Это действительно так, но контроллер фонового представления никогда не снимается с иерархии представлений (отредактирован, чтобы добавить ссылку на это поведение: https://developer.apple.com/documentation/uikit/uimodalpresentationstyle). Таким образом, viewWillAppear никогда не вызывается, поэтому полупрозрачность никогда не удаляется.

Очевидно, что я могу прибегнуть к взломам, например, с помощью NSNotificationCenter и отключить уведомление при удалении OverlayViewController, но это похоже на окольный способ сделать то, что должно быть простым. Есть ли другой способ, которым я могу изящно достичь этого?

Сводные вопросы:

1) Если UIModalPresentationOverCurrentContext - единственный способ достичь этого, то мне интересно, будет ли я вынужден поставить две версии кода, чтобы заставить его работать как в iOS7, так и в iOS8.

2) Очевидно, что новое перечисление не распознается в более ранних версиях Xcode. Итак, если моя команда обновится до Xcode 6, чтобы убедиться, что они могут запускать этот код, даже если остальная часть их работы сосредоточена только на iOS7? Или есть способ сообщить старшей версии Xcode игнорировать конкретный блок кода, который нужен только для iOS8?

Ответ 1

Вам нужно обрабатывать две конфигурации для iOS 7 и iOS8. В обоих случаях вам необходимо убедиться, что контроллер фонового изображения не снят с иерархии представлений. Это можно выполнить с помощью:

  • На iOS7, установив флаг modalPresentationStyle на UIModalPresentationCurrentContext для контроллера представления представления. Вам нужно определить, кто является контроллером представления: он не обязательно self.navigationController, если у вас несколько контроллеров представления контейнеров.

  • На iOS8, установив флаг modalPresentationStyle на UIModalPresentationOverCurrentContext для представленного контроллера. Если вы используете раскадровку, убедитесь, что для стиля презентации установлено значение "По умолчанию" для раскладки раскадровки, а в методе prepareForSegue для стиля представления для диспетчера режима назначения установите UIModalPresentationOverCurrentContext.

Теперь, чтобы ответить на ваши вопросы:

1) Для iOS7 и iOS8 необходимо иметь код для обработки как ситуации:

Определите некоторые макросы, чтобы проверить номер версии приложения. Например, следующее:

#define SYSTEM_VERSION_EQUAL_TO(v)                  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v)              ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v)                 ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v)     ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)

2) Очевидно, что если у вас есть код, который необходимо скомпилировать на iOS7 и iOS8, чтобы ваша команда теперь обновлялась до последней версии XCode "XCode 6.1".

Ответ 2

В Swift для iOS 8.x:

настройка UIModalPresentationStyle.OverCurrentContext для представления viewController выполняет работу.

    func presentTransparentController(){
        var viewController = self.storyboard?.instantiateViewControllerWithIdentifier("ViewControllerNamed") as! ViewController

        // set to .OverCurrentContext
        viewController.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext

        // presents the view controller as usual
        self.presentViewController(viewController, animated: true, completion: nil)
    }

Ответ 3

Основываясь на ответе @Tiguero, я создал небольшой класс категорий для решения проблемы.

@implementation UIViewController (Extensions)

- (void) presentTransparentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion
{
    if(SYSTEM_VERSION_LESS_THAN(@"8.0")) {
        self.parentViewController.navigationController.modalPresentationStyle = UIModalPresentationCurrentContext;
    }else{
        viewControllerToPresent.modalPresentationStyle = UIModalPresentationOverCurrentContext;
    }

    [self presentViewController:viewControllerToPresent animated:YES completion:completion];
}

@end

Версия iOS7 требовала от меня жесткого кода контроллера, который выполняет презентацию.