Полноэкранное воспроизведение MPMoviewPlayerController с базовым UIViewController только с портретным режимом (вращение запрещено)
Алло,
У меня есть простое приложение, которое содержит UITabBarController с двумя UIViewControllers. Оба UIViewControllers являются только портретами (разрешение вращения не разрешено). Один UIViewController UIView имеет представление MPMoviePlayerController, чтобы разрешить воспроизведение видео в этом представлении с возможностью сделать его в полноэкранном режиме с помощью элементов управления (MPMovieControlStyleEmbedded). Код прост и выглядит как...
__moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL URLWithString:@"MOVIE_URL"]];
__moviePlayer.controlStyle = MPMovieControlStyleEmbedded;
__moviePlayer.view.frame = CGRectMake( 10, 10, 300, 200 );
__moviePlayer.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
__moviePlayer.shouldAutoplay = NO;
[__moviePlayer prepareToPlay];
[self.view addSubview:__moviePlayer.view];
... это отлично работает, если пользователь не переключится на полноэкранное воспроизведение, где я хочу разрешить поворот, чтобы можно было воспроизводить пейзаж. Вращение не работает, потому что UITabBarController запрещает его (и оба UIViewControllers тоже).
Итак, я попробовал два подхода, но ни один из них не работает должным образом.
1) Подклассифицированный UITabBarController
Я добавил свойство BOOL __allowRotation, и если он установлен в YES, я возвращаю YES в UITabBarController shouldAutorotateToInterfaceOrientation.
Я слушаю MPMoviePlayerDidEnterFullscreenNotification и MPMoviePlayerWillExitFullscreenNotification уведомления, чтобы установить это свойство в YES и NO.
Это работает, но проблема в том, что когда пользователь заканчивает воспроизведение видео в ландшафтном режиме, основной вид не поворачивается назад к портрету. Единственный способ повернуть назад к портрету - использовать частный API, который нет.
2) Просмотр/преобразование слоев
Я также попытался прослушать уведомления MPMoviePlayerDidEnterFullscreenNotification и MPMoviePlayerWillExitFullscreenNotification.
Когда я получаю MPMoviePlayerDidEnterFullscreenNotification, я начинаю уведомления о ориентации UIDevice, чтобы получить ориентацию устройства. Я пытаюсь преобразовать слой представления MPMoviePlayerController, основанный на текущей ориентации устройства, но он невосприимчив, потому что он ничего не делает. Я могу назначить все для преобразования свойства, но ничего не делает.
Делает ничего не совсем правильно. Когда я применяю преобразование во время вращения, я могу увидеть эффект этого преобразования, когда я переключаюсь с полноэкранного воспроизведения на встроенное видео.
3) Разделите UIWindow
Я еще не тестировал это, но где-то я нашел, что MPMoviePlayerController создает отдельный UIWindow для полноэкранного воспроизведения, который должен быть доступен через окна [[UIApplication sharedApplication]]. Это объясняет, почему преобразование не применяется во время полноэкранного воспроизведения.
Но я очень не люблю это решение, потому что UIWindow не может быть идентифицирован, и я не хочу использовать магические константы, такие как objectAtIndex: 1 или применить преобразование ко всем UIWindows, кроме основного, и т.д.
Кроме того, что базовая реализация может быть изменена, и она перестанет работать.
Вопрос
Итак, вопрос в том, как разрешить полноэкранному воспроизведению MPMoviePlayerController только вращение, когда базовый UIView (то есть UIView UIViewController) запрещает поворот и позволяет только портрет?
Ответы
Ответ 1
Вы можете попытаться представить новый UIViewController (с mustAutorotate YES) по умолчанию и добавить __moviePlayer.view в этот контроллер, когда он отправит MPMoviePlayerWillEnterFullscreenNotification. Сделайте обратное, когда moviePlayer выйдет из полноэкранного режима.
Ответ 2
У меня очень похожая ситуация. Мое приложение - только для портрета. Но мне нужно показать полноэкранные видеоролики в любой ориентации, а затем вернуться к портретной ориентации после выхода из полноэкранного режима.
Сплит-метод не работает для меня, потому что я хотел бы позволить пользователю смотреть видео в полноэкранном режиме и встроенном, а также переключаться между режимами, не теряя позицию воспроизведения, и без каких-либо пауз.
Я нашел это обходное решение:
Сначала у меня есть корневой подкласс UINavigationController, который получает все сообщения относительно вращения.
Я запрещаю вращение в этом контроллере с помощью:
- (BOOL) shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)toInterfaceOrientation {
return (UIInterfaceOrientationPortrait == toInterfaceOrientation);
}
Я переопределяю
- (id) initWithRootViewController:(UIViewController *)rootViewController; method.
Добавление поддержки модификаций ориентации устройства:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(receivedRotate:) name: UIDeviceOrientationDidChangeNotification object: nil];
Теперь у меня есть обработчик, полученныйRotate: - который ловит все вращения устройства, несмотря на то, что он не поворачивается автоматически к любым ориентациям, кроме портрета:
- (void) receivedRotate:(NSNotification*) notify {
if(isVideoFullscreen) {
UIDeviceOrientation toInterfaceOrientation = [[UIDevice currentDevice] orientation];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.4];
[UIView setAnimationCurve:2];
if(toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft){
self.view.transform = CGAffineTransformMakeRotation(-M_PI_2);
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeLeft];
self.view.bounds = CGRectMake(0, 0, 1024, 768);
} else if(toInterfaceOrientation == UIInterfaceOrientationLandscapeRight) {
self.view.transform = CGAffineTransformMakeRotation(M_PI_2);
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight];
self.view.bounds = CGRectMake(0, 0, 1024, 768);
} else if(toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
self.view.transform = CGAffineTransformMakeRotation(M_PI);
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortraitUpsideDown];
self.view.bounds = CGRectMake(0, 0, 768, 1024);
} else if(toInterfaceOrientation == UIInterfaceOrientationPortrait) {
self.view.transform = CGAffineTransformMakeRotation(0);
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait];
self.view.bounds = CGRectMake(0, 0, 768, 1024);
}
[UIView commitAnimations];
}
}
Я просто проверяю вращения устройства и соответственно поворачиваю свое представление.
Затем - как знает корневой контроллер, когда видео полноэкранное?
Просто добавьте два других обработчика сообщений в init:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willEnterFullscreen:) name:MPMoviePlayerWillEnterFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willExitFullscreen:) name:MPMoviePlayerWillExitFullscreenNotification object:nil];
И сами обработчики:
- (void) willEnterFullscreen: (NSNotification *) notify {
isVideoFullscreen = YES;
}
- (void) willExitFullscreen: (NSNotification *) notify {
self.view.transform = CGAffineTransformMakeRotation(0);
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait];
self.view.bounds = CGRectMake(0, 0, 768, 1024);
isVideoFullscreen = NO;
}
При выходе из полноэкранного режима - мы восстанавливаем портретную ориентацию.
Итак, это работает для меня, надеюсь, что это поможет кому-то.
Ответ 3
Зарегистрируйтесь для MPMoviePlayerWillExitFullscreenNotification и MPMoviePlayerWillEnterFullscreenNotification в делегате приложения и обрабатывайте ориентацию с использованием переменной экземпляра.
-(void)moviePlayerFullScreen:(NSNotification *)notification
{
if ([notification.name isEqualToString:@"MPMoviePlayerWillEnterFullscreenNotification"]) {
self.supportedOrientation=UIInterfaceOrientationMaskAll;
}
else if ([notification.name isEqualToString:@"MPMoviePlayerWillExitFullscreenNotification"])
{
self.supportedOrientation=UIInterfaceOrientationMaskPortrait;
}
}
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
return self.supportedOrientation;
}
Ответ 4
MPMoviePlayerViewController имеет свою собственную функцию для видеороликов:
NSURL *videoURL = [NSURL fileURLWithPath:video.path];
moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:videoURL];
//Calls for movie playback once video is finished
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:moviePlayer];
playerView = [[MPMoviePlayerViewController alloc]init];
[moviePlayer setControlStyle:MPMovieControlStyleFullscreen];
[playerView setView:moviePlayer.view];
[moviePlayer.view setFrame: self.view.bounds];
[self presentMoviePlayerViewControllerAnimated:playerView];
[moviePlayer play];
NSLog(@"playing video view");
Ответ 5
Привет всем, у меня была такая же проблема, я ее разрешил -
Вот мой полный код....
Вам нужно сначала изменить appdelegate:
-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if ([[[NowPlaying sharedManager] playerViewController] allowRotation])//Place your condition here
{
return UIInterfaceOrientationMaskAll;
}
return UIInterfaceOrientationMaskPortrait;
}
Регистрация Уведомления для полноэкранного управления:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(moviePlayerWillEnterFullscreenNotification:)
name:MPMoviePlayerWillEnterFullscreenNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(moviePlayerWillExitFullscreenNotification:)
name:MPMoviePlayerWillExitFullscreenNotification
object:nil];
Затем добавьте строку кода в контроллер плеера:
- (void)moviePlayerWillEnterFullscreenNotification:(NSNotification *)notification
{
dispatch_async(dispatch_get_main_queue(), ^
{
self.allowRotation = YES;
});
}
- (void)moviePlayerWillExitFullscreenNotification:(NSNotification *)notification
{
self.allowRotation = NO;
[self.moviePlayerController setControlStyle:MPMovieControlStyleNone];
dispatch_async(dispatch_get_main_queue(), ^
{
//Managing GUI in pause condition
if (self.currentContent.contentType == TypeVideo && self.moviePlayerController.playbackState == MPMoviePlaybackStatePaused)
{
[self.moviePlayerController pause];
if (self.playButton.selected)
self.playButton.selected = NO;
}
self.view.transform = CGAffineTransformMakeRotation(0);
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait];
self.view.bounds = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);
});
}
Этот код проверен в iOS6 и iOS7. Благодаря
Пожалуйста, дайте мне знать, если есть какие-либо вопросы.....