I created an UIWebView inside an UIViewController. This web view contains a youtube video page like this one: http://www.youtube.com/watch?v=oL1RE8JXaIw
When I click on the video link, the iOS video player is launched. Everything is going well till here.
The problem is that when I rotate my application (in landscape mode) and I click on the done button, my View Controller is in landscape mode.
So I've added this callback in the view controller:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return NO;
}
but nothing has changed.
Any idea?
That orientation code is invalid - make sure to always return YES for at least one orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return UIInterfaceOrientationPortrait;
}
I handled that problem using NSNotification like this in viewDidLoad method
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerDidExitFullScreen)
name:#"UIMoviePlayerControllerDidExitFullscreenNotification"
object:nil];
and this method will call when video ends and you can do necessary changes
- (void)moviePlayerDidExitFullScreen
{
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if (orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight || orientation == UIInterfaceOrientationPortraitUpsideDown)
{
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait];
}
}
Hope that Helps
Related
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?
I am attempting to make the youtube video that is in my UIWebView go into landscape but my application is only set to portrait and i don't want anything else to be landscape. I have already tried many things for example supporting landscape and on all the other views returning no to landscape but its not working. My project is a tab based application. If i have to the whole view can rotate and not just the video but if just the youtube video could rotate once its gone into fullscreen(which happens automatically) it would be brilliant.
You could make your controller subscribe to the UIDeviceOrientationDidChangeNotification notification and from the method handling the notification rotate just the UIWebView containing the video.
This would be something like this:
[[NSNotificationCenter defaultCenter] addObserver:self
selector: #selector(handleOrientationChangeNotification:)
name: UIDeviceOrientationDidChangeNotification object:nil];
-(void)handleOrientationChangeNotification:(NSNotification *)notification
{
UIDeviceOrientation currentDeviceOrientation = [[UIDevice currentDevice] orientation];
if (currentDeviceOrientation == UIDeviceOrientationLandscapeRight) {
webView.transform = CGAffineTransformRotateMake(M_PI_2);
webView.bounds = (CGRect){480,320};
webView.center = (CGPoint){240,160};
} else if (...
...
}
I wanted to make my project support full orientation.
I'm on xcode 4.2
My implementation gives me one warning:
that's the code :
#import "OrientationTutorialViewController.h"
#implementation OrientationTutorialViewController
#synthesize portraitView, landscapeView;
- (void)viewDidLoad
{
[super viewDidLoad];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(orientationChanged:) name:#"UIDeviceOrientationDidChangeNotification" object:nil];
}
- (void) orientationChanged:(id)object
{
UIInterfaceOrientation interfaceOrientation = [[object object] orientation];
if (interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)
{
self.view = self.portraitView;
}
else
{
self.view = self.landscapeView;
}
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
- (void)dealloc
{
[super dealloc];
}
#end
Is there a way to fix this warning?
I'm guessing you copied this code from this tutorial. This shows the danger of just copying and pasting code from some random person on the Internet.
There are a few problems with this code. First, there's the issue you describe here, where the UIDeviceOrientationDidChangeNotification notification passes back a UIDevice, whose -orientation method returns a UIDeviceOrientation enum. For some reason, the author of this code is assigning that value to a UIInterfaceOrientation enum, instead of dealing with it as a UIDeviceOrientation value. This could be fixed by using the appropriate enum type and comparing against those values.
Second, why are they using a notification for orientation changes, when they just as easily could be using the UIViewController delegate method -didRotateFromInterfaceOrientation:? That does pass in a UIInterfaceOrientation enum. I recommend replacing the notification and the responder method above with -didRotateFromInterfaceOrientation:. See Apple's many examples of view controller autorotation, as well as their copious documentation, for how to do this.
Third, if they're going to have a method respond to a notification, like in -orientationChanged: above, it should take an NSNotification object, not just a generic id.
I have tried so many of these alternatives, then I found out that you also have to be sure to change the variabel Initial interface orientation to what you want in addition to adding
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
return (self.interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
somewhere in your implementation file. Just the snippet worked in the beginning, but when adding more views and controllers, it all got messed up until I changed the .plist.
After reading many posts, I still haven't got a clue how to solve this problem...
The first view of my app is a tableViewController. I override
(BOOL) shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation
and it always returns YES.
If I hold my iPad upright under landscape orientation, it rotates right after I launch the app. However, if I put my iPad flat on the table, even though my homepage is in landscape orientation, it launches in protrait orientation.
So I guess the problem is, how can I get the orientation of my homepage and launch my app with that orientation?
I had this same problem. There's some funky stuff that goes on with the first view controller you add to a window and whatever orientation it has. Make sure that the view controllers all return YES for orientations if you want the very first one to open with the right orientation
My app is openGL, but the way I handled this was to use notifications:
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
// This is called right BEFORE the view is about to rotate. Here I'm using a notification message
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
if (UIInterfaceOrientationIsPortrait(toInterfaceOrientation)) {
NSNotification* notification = [NSNotification notificationWithName:#"orientationIsPortrait" object:self];
[[NSNotificationCenter defaultCenter] postNotification:notification];
}
else {
NSNotification* notification = [NSNotification notificationWithName:#"orientationIsLandscape" object:self];
[[NSNotificationCenter defaultCenter] postNotification:notification];
}
}
willRotateToInterfaceOrientation is called right BEFORE it actually starts rotating the orientation.
Then in my EAGLView initWithFrame: I set up observers..
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(viewBecamePortrait:) name:#"orientationIsPortrait" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(viewBecameLandscape:) name:#"orientationIsLandscape" object:nil];
and in viewBecamePortrait and viewBecameLandscape I handle the changes programatically.
On application start willRotateToInterfaceOrientation used only in case if "Home" screen in Landscape mode.
This way we can detect orientation when device is "Face Up" or "Face Down".
[UIDevice currentDevice].orientation work in case if device not parallel to ground.
I used the statusbar orientation to orient my openglview, like this:
UIDeviceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
NSLog(#"%s: orientation: %i", _cmd, (int)orientation);
In a given event handler (not the "shouldAutorotateToInterfaceOrientation" method) how do I detect the current iPad orientation? I have a text field I have to animate up (when keyboard appears) in the Landscape view, but not in the portrait view and want to know which orientation I'm in to see if the animation is necessary.
Orientation information isn't very consistent, and there are several approaches. If in a view controller, you can use the interfaceOrientation property. From other places you can call:
[[UIDevice currentDevice] orientation]
Alternatively, you can request to receive orientation change notifications:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
Some people also like to check the status bar orientation:
[UIApplication sharedApplication].statusBarOrientation
I think
[[UIDevice currentDevice] orientation];
is not really reliable. Sometimes it works, sometimes not... In my apps, I use
[[UIApplication sharedApplication]statusBarOrientation];
and it works great!
One of:
Check the interfaceOrientation property of the active view controller.
[UIApplication sharedApplication].statusBarOrientation.
[UIDevice currentDevice].orientation. (You may need to call -beginGeneratingDeviceOrientationNotifications.)
I found a trick to solve the FaceUp orientation issue!!!
Delay the orientation check till AFTER the app has started running, then set variables, view sizes, etc.!!!
//CODE
- (void)viewDidLoad {
[super viewDidLoad];
//DELAY
[NSTimer scheduledTimerWithTimeInterval:0.5
target:self
selector:#selector(delayedCheck)
userInfo:nil
repeats:NO];
}
-(void)delayedCheck{
//DETERMINE ORIENTATION
if( [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortrait ){
FACING = #"PU";
}
if( [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortraitUpsideDown ){
FACING = #"PD";
}
if( [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft ){
FACING = #"LL";
}
if( [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight ){
FACING = #"LR";
}
//DETERMINE ORIENTATION
//START
[self setStuff];
//START
}
-(void)setStuff{
if( FACING == #"PU" ){
//logic for Portrait
}
else
if( FACING == #"PD" ){
//logic for PortraitUpsideDown
}
else{
if( FACING == #"LL"){
//logic for LandscapeLeft
}
else
if( FACING == #"LR" ){
//logic for LandscapeRight
}
}
//CODE
You can addSubviews, position elements, etc. in the 'setStuff' function ... anything that would initially depend on the orientation!!!
:D
-Chris Allinson
You can achieve this by two ways:
1- By using the following method:
**Put the following line in the -(void)viewDidLoad Method:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(deviceRotated:) name:UIDeviceOrientationDidChangeNotification object:nil];
then put this method inside your class
-(void)deviceRotated:(NSNotification*)notification
{
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
if(orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight)
{
//Do your textField animation here
}
}
The above method will check the orientation when the device will be rotated
2- The second way is by inserting the following notification inside -(void)viewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(checkRotation:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
then put the following method inside your class
-(void)checkRotation:(NSNotification*)notification
{
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if(orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight)
{
//Do your textField animation here
}
}
The above method will check the orientation of the status bar of the ipad or iPhone and according to it you make do your animation in the required orientation.
For determining landscape vs portrait, there is a built-in function:
UIInterfaceOrientation orientation = [[UIDevice currentDevice] orientation];
BOOL inLandscape = UIDeviceOrientationIsLandscape(orientation);
[UIApplication sharedApplication].statusBarOrientation returns portrait when it's landscape, and landscape when it's portrait at launch, in iPad
I don't know why, but every time my app starts, the first 4 are right, but subsequently I get the opposite orientation. I use a static variable to count this, then have a BOOL to flip how I manually send this to subviews.
So while I'm not adding a new stand-alone answer, I'm saying use the above and keep this in mind. Note: I'm receiving the status bar orientation, as it's the only thing that gets called when the app starts and is "right enough" to help me move stuff.
The main problem with using this is the views being lazily loaded. Be sure to call the view property of your contained and subviews "Before" you set their positions in response to their orientation. Thank Apple for not crashing when we set variables that don't exist, forcing us to remember they break OO and force us to do it, too... gah, such an elegant system yet so broken! Seriously, I love Native, but it's just not good, encourages poor OO design. Not our fault, just reminding that your resize function might be working, but Apple's Way requires you load the view by use, not by creating and initializing it
In your view controller, get the read-only value of self.interfaceOrientation (the current orientation of the interface).
I've tried many of the above methods, but nothing seemed to work 100% for me.
My solution was to make an iVar called orientation of type UIInterfaceOrientation in the Root View Controller.
- (void)viewDidLoad {
[super viewDidLoad];
orientation = self.interfaceOrientation; // this is accurate in iOS 6 at this point but not iOS 5; iOS 5 always returns portrait on app launch through viewDidLoad and viewWillAppear no matter which technique you use.
}
- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
return YES;
}
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
orientation = toInterfaceOrientation;
}
Then, any place where you need to check the orientation you can do something like this:
if(UIInterfaceOrientationIsPortrait(orientation)){
// portrait
}else{
// landscape
}
There may still be a better way, but this seems to work 98% of the time (iOS5 notwithstanding) and isn't too hard. Note that iOS5 always launches iPad in portrait view, then sends a device the willRotateTo- and didRotateFromInterfaceOrientation: messages, so the value will still be inaccurate briefly.
[UIDevice currentDevice].orientation works great.
BUT!!!
... the trick is to add it to - (void)viewWillAppear:(BOOL)animated
exp:
(void)viewWillAppear:(BOOL)animated{
...
BOOL isLandscape = UIInterfaceOrientationIsLandscape(self.interfaceOrientation);
...
}
If you call it at - (void)viewDidLoad, it does not work reliable, especially if you use multiple threads (main UI thread, background thread to access massive external data, ...).
Comments:
1) Even if your app sets default orientation portrait, user can lock it at landscape. Thus setting the default is not really a solution to work around it.
2) There are other tasks like hiding the navigation bar, to be placed at viewWillAppear to make it work and at the same time prevent flickering. Same applies to other views like UITableView willDisplayCell -> use it to set cell.selected and cell.accessoryType.