Поворот полноэкранного воспроизведения MPMoviewPlayerController с базовым UIViewController только в портретном режиме (вращение запрещено) - PullRequest
12 голосов
/ 16 февраля 2011

Алло,

У меня есть простое приложение, которое содержит UITabBarController с двумя UIViewController. Оба UIViewControllers являются только портретными (вращение не допускается). UIView одного UIViewController содержит представление 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 в методе shouldAutorotateToInterfaceOrientation UITabBarController.

Я слушаю уведомления MPMoviePlayerDidEnterFullscreenNotification и MPMoviePlayerWillExitFullscreenNotification, чтобы установить для этого свойства значение YES и NO.

Это работает, но проблема в том, что, когда пользователь заканчивает воспроизведение видео в альбомной ориентации, базовый вид не поворачивается обратно в портретную. Единственный способ вернуться к портретному изображению - использовать закрытый API, которого нет.

2) Вид / преобразование слоя

Я также пытался прослушивать уведомления MPMoviePlayerDidEnterFullscreenNotification и уведомления MPMoviePlayerWillExitFullscreenNotification.

Когда я получаю MPMoviePlayerDidEnterFullscreenNotification, я запускаю уведомления об ориентации UIDevice, чтобы получить ориентацию устройства. Я пытаюсь преобразовать слой представления MPMoviePlayerController, основываясь на текущей ориентации устройства, но это своего рода иммунитет, потому что он ничего не делает. Я могу присвоить что угодно для преобразования свойства, но оно ничего не делает.

Это ничего не делает, не совсем правильно. Когда я применяю преобразование во время поворота, я вижу эффект этого преобразования, когда я переключаюсь из полноэкранного в режим воспроизведения встроенного видео.

3) Отдельное UIWindow

Я еще не тестировал это, но где-то обнаружил, что MPMoviePlayerController создает отдельное UIWindow для полноэкранного воспроизведения, которое должно быть доступно через [[UIApplication sharedApplication] windows]. Это объясняет, почему преобразование не применяется во время полноэкранного воспроизведения.

Но мне очень не нравится это решение, потому что UIWindow не может быть идентифицировано, и я не хочу использовать магические константы, такие как objectAtIndex: 1 или применять преобразование ко всем UIWindows, кроме основного и т. Д.

Кроме того, что базовая реализация может быть изменена, и она перестанет работать.

Вопрос

Итак, вопрос в том, как разрешить поворот полноэкранного воспроизведения MPMoviePlayerController только тогда, когда нижележащий UIView (т. Е. UIViewController UIView) запрещает поворот и разрешает только портрет?

Ответы [ 5 ]

8 голосов
/ 25 марта 2012

У меня очень похожая ситуация. Мое приложение только для портрета. Но мне нужно показать полноэкранное видео в любой ориентации, а затем вернуться к книжной ориентации после того, как пользователь выйдет из полноэкранного режима.

Метод Сплита не работает для меня, потому что я хотел бы позволить пользователю просматривать видео в полноэкранном и встроенном режиме и переключаться между режимами, не теряя позиции воспроизведения и без каких-либо пауз.

Я нашел этот обходной путь:

Во-первых, у меня есть корневой подкласс 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];

Теперь у меня есть обработчик receiveRotate: - который улавливает все повороты устройства, несмотря на то, что он не вращается автоматически в любую ориентацию, кроме книжной:

- (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;
}

При выходе из полноэкранного режима - восстанавливаем портретную ориентацию. Так что это работает для меня, надеюсь, это поможет кому-то.

6 голосов
/ 16 февраля 2011

Вы можете попробовать представить новый UIViewController (с shouldAutorotate YES) модально и добавить __moviePlayer.view в этот контроллер, когда он отправляет MPMoviePlayerWillEnterFullscreenNotification. Сделайте обратное, когда moviePlayer выходит из полноэкранного режима.

1 голос
/ 31 октября 2013

Зарегистрируйтесь для 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;
}

0 голосов
/ 08 апреля 2014

Привет всем, у меня была такая же проблема, я решил ее -

Вот мой полный код ....

Вам необходимо сначала изменить 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 работает нормально.Спасибо

Пожалуйста, дайте мне знать, если есть какие-либо вопросы .....

0 голосов
/ 23 июля 2012

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");
...