Как представить контроллер просмотра в портретном или ландшафтном режиме, в приложении, предназначенном только для портрета
У меня есть приложение для iPhone, большинство из которых только для портрета, но с одним контроллером представления (экран видеоплеера), который должен поддерживать как портрет, так и пейзаж (это только для iOS 8). Чтобы достичь этого, я установил приложение plist для поддержки портрета и обоих видов ландшафта, а затем подкласса UINavigationController
; в этом подклассе я переопределяю
- (BOOL)shouldAutorotate {
return YES;
}
и
- (NSUInteger)supportedInterfaceOrientations {
if ([self.visibleViewController isKindOfClass:[MyVideoPlayerScreen class]]) {
return UIInterfaceOrientationMaskAllButUpsideDown;
} else {
return UIInterfaceOrientationMaskPortrait;
}
}
Это в основном работает так, как ожидалось: начальные экраны - только портретные и остаются в портрете, даже когда устройство повернуто к пейзажу. Видеопроигрыватель при первоначальном представлении:
MyVideoPlayerScreen *newVC = [MyVideoPlayerScreen new];
[self.navigationController pushViewController:newVC animated:YES];
также находится в портрете, но затем поворачивается к пейзажу, когда устройство повернуто - все хорошо до сих пор.
Проблема заключается в том, что если я превращу устройство в альбомное, видеопроигрыватель тоже будет ландшафтным, но затем, когда я уберу экран видеопроигрывателя с помощью кнопки "Назад", основной контроллер представления (который должен быть только портретным ) теперь также в ландшафте. Если я верну устройство обратно к портрету, контроллер просмотра снова вернется к портрету, и затем он будет правильно зафиксирован только в портретном режиме с этой точки.
Как я могу получить исходный контроллер представления (который должен быть только для портрета), чтобы автоматически вернуться к портрету, когда над ним выскочил контроллер ландшафтного вида?
Этот вопрос задан в миллион раз, но, похоже, исправления, которые были отправлены для него, - это все хаки, которые больше не работают в iOS 8.
Обновление: Я нашел исправление типа для этого, которое работает в iOS 8. В моем подклассе UINavigationController
я обрабатываю протокол <UINavigationControllerDelegate>
. Я применил этот метод:
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
if (![viewController isKindOfClass:[MyVideoPlayerScreen class]]) {
// if the current orientation is not already portrait, we need this hack in order to set the root back to portrait
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
if (orientation != UIInterfaceOrientationPortrait) {
// HACK: setting the root view controller to nil and back again "resets" the navigation bar to the correct orientation
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
UIViewController *vc = window.rootViewController;
window.rootViewController = nil;
window.rootViewController = vc;
}
}
}
Это, по крайней мере, оставляет пользовательский интерфейс в состоянии, в котором я хочу, чтобы он находился. Проблема в том, что когда диспетчер представлений верхнего уровня уволен и анимирован за кадром, основной контроллер представления все еще находится в ландшафте; затем он внезапно перескакивает на портрет. Не идеально, но лучше, чем ничего.
Обновление 2: Я должен был добавить, что я нажимаю второй контроллер представлений следующим образом:
ViewControllerPortraitLandscape *newVC = [ViewControllerPortraitLandscape new];
[self.navigationController pushViewController:newVC animated:YES];
Обновление 3: ОК, это вполне выполнимо, что работает для iOS 6 и выше. Исправление даже имеет смысл, хотя причина его работы, похоже, не в документации. В принципе, в контроллере представления вам нужно быть reset на портрете, когда диспетчер представлений верхнего уровня отклоняется, пока устройство по-прежнему находится в ландшафте, вам просто нужно добавить это:
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
Хотя мой подкласс UINavigationController
полностью отвечает за вызовы вращения, точки останова показывают, что supportedInterfaceOrientations
вызывается на базовом контроллере представления перед тем, как высший уровень отклоняется, и он вызвал контроллер навигации после верхнего уровня -level отклоняется. Поэтому я предполагаю, что этот вызов самому контроллеру представления сделан iOS, чтобы определить, на какую ориентацию должен находиться основной контроллер представления (и для этого он не запрашивает навигационный контроллер); если он явно не переопределен, он вернет параметр all-but-upside-down, поэтому iOS просто оставляет его там, где он есть, в ландшафте.
Ответы
Ответ 1
Оказывается, это простое решение: вы можете управлять всем процессом через подкласс UINavigationController
, как я разместил здесь (т.е. не внедрять ни один из этих методов вращения в самих контроллерах представления), за исключением того, что для любого контроллера вида который должен быть только портретным, вам также необходимо реализовать это:
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
С точками останова вы можете видеть, что этот метод вызывается до того, как выше установленный контроллер просмотра выслан; iOS, по-видимому, использует этот вызов для определения того, в какой ориентации должен находиться "обнаруженный" контроллер представления (тот же вызов подкласса контроллера навигации вызывается после того, как диспетчер представления верхнего уровня отклонен).
С помощью этого метода, реализованного в контроллере представления, все работает так, как ожидалось.
Ответ 2
Возьмите портрет EXCEPT при представлении отдельного подкласса UIViewController. Эта статья очень помогла: http://www.fantageek.com/1085/force-only-one-view-controller-to-be-landscape/
установите для Info.plist поддержку, портрет, пейзаж влево, пейзаж справа
реализовать приложение: поддерживаетсяInterfaceOrientationsForWindow: например:
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft;
}
// (I specifically want landscape left for the movie viewing)
подкласс UINavigationController (root's rootController) и переопределяет его так:
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait; // enforces the "portrait everything" requirement
}
Наконец, я должен был убедиться, что пользовательский контроллер просмотра игроков "переопределит" поддерживаемую ориентацию:
- (BOOL)shouldAutorotate
{
return NO;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeLeft;
}
Результат:
Подкласс UIViewController представляет, но при отклонении пользовательского контроллера представления контроллер представления представлений представляет собой портрет.
Из статьи fantageek: "Система пересекает поддерживаемые ориентацией представления контроллеры с ориентациями, поддерживаемыми приложениями (как определено в файле Info.plist или приложении для делегатов приложения: supportedInterfaceOrientationsForWindow: method), чтобы определить, нужно ли вращаться".
Ответ 3
Думаю, вам следует изменить это и повторить попытку
-(NSUInteger)supportedInterfaceOrientations {
if ([self.visibleViewController isKindOfClass:[MyVideoPlayerScreen class]])
{
return UIInterfaceOrientationMaskLandscape;
}
else
{
return UIInterfaceOrientationMaskPortrait;
}
}
Ответ 4
Вот как вы это делаете.
Внедрите эти 3 метода как для представления, так и для представленного контроллера:
- (BOOL)shouldAutorotate {
return NO; //-- for presented controller use YES
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscape; //-- any orientation you need
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationLandscapeRight;
}
и теперь вы можете использовать в контроллере представления:
[self presentViewController:presentedController animated:true completion:nil];
Таким образом, когда вы вернетесь к представителю контроллера, он будет иметь правильную ориентацию.
Ответ 5
В моем случае есть 3 контроллера:
- контроллер первого вида: портрет
- контроллер второго вида: пейзаж справа (имеется контроллер навигации и был представлен контроллером первого вида)
- контроллер третьего вида: портрет (имеет контроллер навигации и был нажат вторым контроллером)
И мое решение уже было здесь. Надеюсь, что это поможет