I have an application entirely in portrait mode. (iOS 5 and above)
I have a video played using MPMoviePlayerController, now in this video i want that when user rotates the iPhone, the video should go to landscape mode(in fullscreen).
When video ends , again the video should go into portrait mode.
Code:
-(void)PlayVideo:(NSURL*)videoUrl
{
moviePlayerController = [[MPMoviePlayerController alloc] initWithContentURL:videoUrl];
[moviePlayerController.view setFrame:CGRectMake(6, 69, 309, 196)];
[self.view addSubview:moviePlayerController.view];
// moviePlayerController.fullscreen = YES;
moviePlayerController.controlStyle = MPMovieControlStyleNone;
[self.view bringSubviewToFront:self.shareView];
[self.view bringSubviewToFront:self.qualityView];
[moviePlayerController play];
// Register to receive a notification when the movie has finished playing.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:moviePlayerController];
}
Rest of the app, i want in portrait only.
How do i achieve this?
First you need to set Support interface orientation to Portrait as well as Landscape
Now in every UIViewController you need to override these methods -
for iOS 5 -
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (BOOL)shouldAutorotate
{
return NO;
}
for iOS 6
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
In UIViewController where you are going to add MPMoviePlayerController override -
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAllButUpsideDown;
}
I created Xcode project with sample of the video player. It can show video on full screen in landscape mode. You can download it . I hope it helps you.
And second. Instead of
[self.view bringSubviewToFront:self.shareView];
[self.view bringSubviewToFront:self.qualityView];
you should write like this:
[moviePlayerController.view insertSubview: self.shareView
atIndex: 2];
[moviePlayerController.view insertSubview: self.qualityView
atIndex: 2];
then shareView and qualityView appears on top of the movie player.
Related
I use XCDYouTubeKit library for my iOS project. I present video from nonFullScreen mode with code:
self.videoPlayer = [[XCDYouTubeVideoPlayerViewController alloc] initWithVideoIdentifier:self.youtubeID];
[self.videoPlayer presentInView:self.videoView];
[self.videoPlayer.moviePlayer play];
When iPhone rotate to landscape mode i set FullScreen video with catching rotate current ViewController:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
if (fromInterfaceOrientation == UIDeviceOrientationPortrait) {
[self.videoPlayer.moviePlayer setFullscreen:YES animated:NO];
}
But how i can catch rotation XCDYouTubeVideoPlayerViewController in fullScreen video mode??
Thank
My decision
in this class i add in viewDidLoad observer
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(handleDidChangeStatusBarOrientationNotification:)
name:UIApplicationDidChangeStatusBarOrientationNotification
object:nil];
And execution
- (void)handleDidChangeStatusBarOrientationNotification:(NSNotification *)notification; {
if ([self.videoPlayer.moviePlayer isFullscreen] && [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortrait) {
[self.videoPlayer.moviePlayer setFullscreen:NO animated:YES];
}
}
I think the easiest way to get this information is to subclass XCDYouTubeVideoPlayerViewController and override didRotateFromInterfaceOrientation: and/or viewWillTransitionToSize:withTransitionCoordinator:
I am having issues of capturing when the youtube player will enter in fullscreen or exit fullscreen in iOS 8 because these notifications were removed UIMoviePlayerControllerDidEnterFullscreenNotification and UIMoviePlayerControllerWillExitFullscreenNotification for this version OS version.
Because my app project is set to be only in portrait mode the video won't rotate to landscape mode when is playing which is really not too user friendly when watching a video on your device.
Usually the user would like to watch the video either in portrait mode or landscape mode when the video enters in fullscreen.
These is the way I was doing it for iOS 7 which was working perfect but not in iOS 8.
First, I will set this function in my AppDelegate.m with boolean property in my AppDelegate.h which I called videoIsInFullscreen and function,
// this in the AppDelegate.h
#property (nonatomic) BOOL videoIsInFullscreen;
// This in my AppDelegate.m to allow landscape mode when the boolean property is set to yes/true.
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
if(self.videoIsInFullscreen == YES)
{
return UIInterfaceOrientationMaskAllButUpsideDown;
}
else
{
return UIInterfaceOrientationMaskPortrait;
}
}
Then within my ViewController.m First, I would #import "AppDelegate.h" after doing this, I will add some notifications in my viewDidLoad method..
-(void)viewDidLoad {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(playerStarted) name:#"UIMoviePlayerControllerDidEnterFullscreenNotification" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(playerEnded) name:#"UIMoviePlayerControllerWillExitFullscreenNotification" object:nil];
}
Of course don't forget to remove them..
-(void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"UIMoviePlayerControllerDidEnterFullscreenNotification" object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"UIMoviePlayerControllerWillExitFullscreenNotification" object:nil];
}
Then, I had my functions that will get call when these notifications get fires... Here is where I allow the landscape mode and then set it back to portrait. These is the case with my app because it's only set to portrait support but I don't want this for the youtube videos.
// first we set our property in the our AppDelegate to YES to allow landscape mode
- (void)playerStarted
{
((AppDelegate*)[[UIApplication sharedApplication] delegate]).videoIsInFullscreen = YES;
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];
}
// Then I will set the property to NO and force the orientation to rotate to portrait.
- (void)playerEnded
{
((AppDelegate*)[[UIApplication sharedApplication] delegate]).videoIsInFullscreen = NO;
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];
}
But, these is not the case for iOS 8.. These notifications no longer work for iOS 8 so, I found something similar using these notifications but I am not too happy because they are not 100% accurate for the video player. UIWindowDidBecomeVisibleNotification and UIWindowDidBecomeHiddenNotification So, how can I do this correctly or at least that works properly for my youtube embedded video and allow landscape mode in iOS 8...?
So, after some research and looking more in-depth to this problem.. I came to a solution using the UIWebView delegates, plus I had to solve another issue in terms of my function - (void)playerEnded which it wasn't working properly in the new iPhone 6 devices..
This is how I did it.. First, in my webViewDidFinishLoad method I have added to my webview a javascript evaluation to check when this video player goes into fullscreen mode..
- (void)webViewDidFinishLoad:(UIWebView*)webView
{
// adding listener to webView
[_webView stringByEvaluatingJavaScriptFromString:#" for (var i = 0, videos = document.getElementsByTagName('video'); i < videos.length; i++) {"
#" videos[i].addEventListener('webkitbeginfullscreen', function(){ "
#" window.location = 'videohandler://begin-fullscreen';"
#" }, false);"
#""
#" videos[i].addEventListener('webkitendfullscreen', function(){ "
#" window.location = 'videohandler://end-fullscreen';"
#" }, false);"
#" }"
];
}
Then, in my - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType method, I check when my request url matches the state of the youtube player, like this..
This will fire our function to allow landscape mode or force back to portrait mode.. or maybe any other type of work you might want to do..
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
// allows youtube player in landscape mode
if ([request.URL.absoluteString isEqualToString:#"ytplayer://onStateChange?data=3"])
{
[self playerStarted];
return NO;
}
if ([request.URL.absoluteString isEqualToString:#"ytplayer://onStateChange?data=2"])
{
[self playerEnded];
return NO;
}
}
And finally, I needed to adjust my playerEnded function to force back portrait mode for iPhone 6 devices..
- (void)playerEnded
{
[[UIDevice currentDevice] setValue:[NSNumber numberWithInteger:UIInterfaceOrientationPortrait] forKey:#"orientation"];
((AppDelegate*)[[UIApplication sharedApplication] delegate]).videoIsInFullscreen = NO;
[self supportedInterfaceOrientations];
[self shouldAutorotate:UIInterfaceOrientationPortrait];
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];
}
Almost, missed I also added these two other functions..
- (NSInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
- (BOOL)shouldAutorotate:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
So, finally I am able to catch the state of the actual player and fire my functions to do some work or whatever I want at the right moment, in my case changing the orientation..
I hope this helps someone else..
I am working on swift, I my player runs movie in both portrait and landscape direction. First I checked three modes : portrait, landscapeleft, landscaperight.
Second I wrote this function in all viewController:
isFullScreen = false
override func shouldAutorotate() -> Bool {
if isFullScreen == true {
return true
}else{
return false
}
}
Third I change the value of isFullScreen in this function:
func playerView(playerView: YTPlayerView!, didChangeToState state: YTPlayerState) {
switch (state) {
case YTPlayerState.Playing:
println("started to play")
isFullScreen == true
shouldAutorotate()
case YTPlayerState.Paused:
println("paused")
default:
println("non of sttate")
break
}
}
And video runs on both portrait and landscape mode! The interesting thing is that I dont set isFullScreen to false again when I pause video or move from fullscreen. However it doesnt rotate! Can somebody explain this?
My whole application is in portrait mode only and i am playing youtube video in my application. For you tube I am using UIWebview. When user click on play button in UIWebview it automatically launch the MPMoviePlayerController. So I did not declared any MPMoviePlayerController object. So I want MPMoviePlayerController support both portrait and landscape orientation. So please suggest.
If you use NavigationController, you could subclass it and do the following:
#import "MainNavigationController.h"
#import <MediaPlayer/MediaPlayer.h>
#implementation MainNavigationController
-(BOOL)shouldAutorotate
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
if ([[[self.viewControllers lastObject] presentedViewController] isKindOfClass:[MPMoviePlayerViewController class]])
{
return UIInterfaceOrientationMaskAll;
}
else
{
return UIInterfaceOrientationMaskPortrait;
}
}
#end
Then you should set your app to support all orientations, and this code will allow orientation change only if it is playing your movie 'MPMoviePlayerController`.
When calling your movie you should send a notification, so if user closes it in any orientation other than portraitit switches back to portrait.
Something like this:
- (IBAction)playButton:(id)sender {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlaybackDidFinish)
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.player.moviePlayer];
NSURL *url = [NSURL URLWithString:videoUrl];
self.player = [[MPMoviePlayerViewController alloc] initWithContentURL:url];
self.player.moviePlayer.movieSourceType = MPMovieSourceTypeFile;
[self presentMoviePlayerViewControllerAnimated:self.player];
}
-(void)moviePlaybackDidFinish
{
[[UIDevice currentDevice] setValue:
[NSNumber numberWithInteger: UIInterfaceOrientationPortrait]
forKey:#"orientation"];
}
This should do it for you, let me know how it goes.
My app accepts only portrait orientation, except for MPMoviePlayerController, which I want to allow user to change orientation.
So, I subclassed UINavigationController and added the following code:
-(BOOL)shouldAutorotate
{
if ([[[self.viewControllers lastObject] presentedViewController] isKindOfClass:[MPMoviePlayerViewController class]])
{
return YES;
}
else
{
return NO;
}
}
It works great, allowing only my MPMoviePlayerViewController to change orientation. The problem is that when user is in landscape orientation and presses the done button or playback ends, it pops the moviePlayer and goes back to the presentingViewController, but on landscape mode, causing a crash, since that view is not made for landscape orientation.
I tried a few things to change back to Portrait but had no luck. I'm using storyboards, if that makes any difference. I would like to change the orientation back to portrait on viewWillAppear, or maybe getting the donebutton press and change the orientation there.
UPDATE:
Here is the updated code in my UINavigationControllersubclass:
-(BOOL)shouldAutorotate
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
if ([[[self.viewControllers lastObject] presentedViewController] isKindOfClass:[MPMoviePlayerViewController class]])
{
return UIInterfaceOrientationMaskAll;
}
else
{
return UIInterfaceOrientationMaskPortrait;
}
}
Now, if I do things in the following order from the view with the Play button.
Rotate the device. (it calls the method but screen doesn't rotate since it is not MPMoviePlayerController class)
Press the play button. (It presents the player already on landscape mode).
Press the back button. (It pops the player and correctly shows the view on portrait mode)
Now, if I change the order to:
Press the play button. (holding the device on the regular portrait position).
Rotate the device. (it rotates the movie player correctly showing the video).
Press the back button. (it pops the player, but this time, the view is in landscape mode, which is not the expected behavior)
Found a solution here on this answer.
On button click, I added a notification and then on done button click I used the below code to change orientation. I kept the UINavigationController subclass as in my question to allow the change of orientation when movie starts playing.
- (IBAction)playButton:(id)sender {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlaybackDidFinish)
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.player.moviePlayer];
NSURL *url = [NSURL URLWithString:#"https://dl.dropboxusercontent.com/s/crzu6yrwt35tgej/flexao.mp4"];
self.player = [[MPMoviePlayerViewController alloc] initWithContentURL:url];
self.player.moviePlayer.movieSourceType = MPMovieSourceTypeFile;
[self presentMoviePlayerViewControllerAnimated:self.player]; // presentMoviePlayerViewControllerAnimated:self.player];
}
-(void)moviePlaybackDidFinish
{
[[UIDevice currentDevice] setValue:
[NSNumber numberWithInteger: UIInterfaceOrientationPortrait]
forKey:#"orientation"];
}
I have a working configuration for your problem, as far as I understand from your question.
You need a subclass of UINavigationController as you already have, but with the following code:
The .h file:
#interface EECNavigationController : UINavigationController
#property (assign, nonatomic) BOOL landscapeDisallowed;
#end
The .m file:
#import "EECNavigationController.h"
#implementation EECNavigationController
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
if( !_landscapeDisallowed ) {
// for iPhone, you could also return UIInterfaceOrientationMaskAllButUpsideDown
return UIInterfaceOrientationMaskAll;
}
return UIInterfaceOrientationMaskPortrait;
}
#end
Now, in the view controllers that will be under this navigation controller that you want to be just portrait you just need to set the "landscapeDisallowed" to YES in the viewDidLoad method, like:
- (void)viewDidLoad {
[super viewDidLoad];
((EECNavigationController *)self.navigationController).landscapeDisallowed = YES;
}
And override the following methods like this:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
return toInterfaceOrientation == UIInterfaceOrientationPortrait;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
The views that can be presented in landscape mode just need to:
- (void)viewDidLoad {
[super viewDidLoad];
((EECNavigationController *)self.navigationController).landscapeDisallowed = NO;
}
It works for me, hope it works for you.
-(void)viewWillAppear:(BOOL)animated
{
[self updateLayoutForNewOrientation:self.interfaceOrientation];
}
- (void)updateLayoutForNewOrientation:(UIInterfaceOrientation)orientation
{
if (self.interfaceOrientation == UIInterfaceOrientationPortrait || self.interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)
{
// Portrait view
if(iPhone5)
{
}else{
}
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.0"))
{
}
}
else
{
// Landscape view
if(iPhone5)
{
}else{
float SystemVersion=[[[UIDevice currentDevice] systemVersion] floatValue];
if(SystemVersion>=7.0f)
{
}else{
}
}
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.0"))
{
if(iPhone5)
{
}
else
{
}
}
}
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
{
[self updateLayoutForNewOrientation:self.interfaceOrientation];
}
Hope this will help
I am working with an app which required to open "MPMoviePlayerViewController" when clicked on a video file.
There is a tabbarController into our app which has four Navigation controllers for four tabs.
My app only support portrait orientation, but video should support both landscape & portrait orientations. So, I make Subclass of "MPMoviePlayerViewController".
Code of that class..
#interface MyMovieViewController : MPMoviePlayerViewController
#end
#implementation MyMovieViewController
-(void)viewDidLoad{
[self setWantsFullScreenLayout:NO];
}
-(void)viewWillDisappear:(BOOL)animated{
[self resignFirstResponder];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return YES;
}
-(BOOL)shouldAutorotate{
return YES;
}
#end
In First tab, I show Gallery. There is a code to open video file.
UIGraphicsBeginImageContext(CGSizeMake(1,1));
MPMoviePlayerViewController * vc = [[MyMovieViewController alloc] initWithContentURL:[[[elcAsset asset] valueForProperty:ALAssetPropertyURLs] valueForKey:[[[[elcAsset asset] valueForProperty:ALAssetPropertyURLs] allKeys] objectAtIndex:0]]];
UIGraphicsEndImageContext();
// Remove the movie player view controller from the "playback did finish" notification observers
[[NSNotificationCenter defaultCenter] removeObserver:vc
name:MPMoviePlayerPlaybackDidFinishNotification
object:vc.moviePlayer];
// Register this class as an observer instead
[[NSNotificationCenter defaultCenter]
addObserver: self
selector: #selector(doneButtonClick:)
name: MPMoviePlayerPlaybackDidFinishNotification
object: vc.moviePlayer];
[self presentMoviePlayerViewControllerAnimated:vc];
[vc.moviePlayer prepareToPlay];
[vc.moviePlayer play];
Video is working file. It also support both orientations. but when I switch to another tab, then no textfield show keyboard when clicked on it.
Please help. Thanks is advance.
I have solved the issue.
Actually, MPMoviePlayerViewController support both orientations and my app support only portrait. When i dismiss MPMoviePlayerViewController,then parentview of it think that it is Landscape mode.
So, it display landscape keyboard, which's CGPoint is lower than screen. Thats why I am not able to see keyboard.
I have make write following code into my CustomNavigationController.
- (BOOL)shouldAutorotate
{
return [self.visibleViewController shouldAutorotate];
}
- (NSUInteger)supportedInterfaceOrientations
{
return [self.visibleViewController supportedInterfaceOrientations];
}
Now, it is working fine.
YOu need to dismiss Your MoviePlayer..
Use this notification that calls when your video is over
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(myMovieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.theMoviePlayer];
and write method of it.
-(void)myMovieFinishedCallback:(NSNotification*)aNotification
{
[self dismissMoviePlayerViewControllerAnimated];
MPMoviePlayerController* theMovie = [aNotification object];
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:theMovie];
}
You can try this delegate method,
(BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar{
[myTextField becomeFirstResponder];
return YES;
}
If this does not work, try to find out what is called after dismissing the view and then insert following code... This will definitely work.
[myTextField becomeFirstResponder];