The problem is that I am launching in-app email and triggering keyboards (via UITextFields) and they are coming up portrait on my landscape app. I am able to rotate it portrait, then rotate it landscape again, observing the black rotation corners animation that occurs when an app rotates from portrait to landscape. Since I've locked out any orientation but landscape right in my shouldAutorotateToInterfaceOrientation() method, the view itself doesn't rotate, which is great. However, when I add these views, the app keeps thinking they are portrait as is evidenced by the UITextField keyboard and in-app email orientation unless I rotate to portrait, then back to landscape (which triggers the autorotate method to return true.
Any suggestions on how I can make this app know it's already in landscape to begin with when I'm adding views?
Update: I had tried setting the status bar orientation, but it does not work for me. I don't know if there's something with the fact that I remove and then add views to the app that is confusing its understanding of the orientation. Do you know how apple objects such as the UITextField and in-app mail determine what orientation to show? Do they simply poll the sharedApplication orientation? The odd thing for me is that it seems like when I remove and add new views, these apple widgets that I've tilted the phone to change to landscape suddenly revert to showing as portrait. i.e. this general sequence of events:
1) app in landscape, trigger keyboard, it shows portrait
2) tilt device to make it go into landscape. close and open keyboard and it's in landscape.
3) remove and add some views.
4) trigger keyboard again, it shows up in portrait
[UIApplication setStatusBarOrientation:animated:] should give you what you want.
Setup Initial interface orientation field in Project plist
Interestingly, I found that setting the status bar orientation at the launch was not enough. Watching the field value, I noticed it was resetting to portrait at various times, such as when returning from canceling an in-app mail. I found making multiple calls to set the status bar seems to address the problem. Thanks for the input, mbehan.
Removing/adding views shouldn't change the status bar orientation; as far as I know, that defaults to the view controller's orientation unless you set it explicitly (and then you have to be careful, because view controllers reset it). You can try using UIStatusBarStyleBlackTranslucent and setting UIViewController.wantsFullScreenLayout on your VCs to see what's going on.
(In the past, I've noticed it getting confused when I add a view to the window directly, on top of a portrait-only view. It seems to work in all other cases though...)
What's your implementation(s) of shouldAutorotateToInterfaceOrientation:?
try this:
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
//Rotate the complete view to look like landscape view
[self rotateToLandscape];
}
and the rotation method;
-(void)rotateToLandscape
{
UIWindow *win = [[UIApplication sharedApplication]keyWindow];
if(UIInterfaceOrientationIsPortrait(self.interfaceOrientation)){
[[[UIApplication sharedApplication] keyWindow] setBackgroundColor:[UIColor blackColor]];
[UIView beginAnimations:#"View Flip" context:nil];
[UIView setAnimationDuration:0.3];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
win.transform = CGAffineTransformIdentity;
win.transform = CGAffineTransformMakeRotation(degreesToRadian(90));
win.bounds = CGRectMake(0.0f, 0.0f, 480, 320);
win.center = CGPointMake(160.0f, 240.0f);
[UIView commitAnimations];
}
}
Related
I browsed through most of the questions and tried almost everything. But bad part is that the issue is still there.
I have a UIVIew which is always launched in landscape mode and I am presenting a second view (detailView) as a full screen modal view.
The detailview has a UIwebview on top of it.
When I present the detailView as a modal view, the webview is being shown in portrait mode.
I am returning "YES" in shouldAutoRotateToInterfaceOrientation and also have set autoresize , autoresizingMask and scalePageToFit properties.
When I rotate the device, and when the detailView is in front, the webview arranges to landscape properly.
The issue is only when I present the modalView for the first time.
Rotating the device is adjusting the layout properly.
As far as I am aware ModalViews on the iPhone do not support Landscape View. The case may be different for iPhone 5.
But it sounds like you are setting the ModalView not the WebView to landscape, I'd suggest a different approach to handling this.
For Example you could animate the DetailView in like a ModalView so it starts in the correct orientation
If you are running your app on iOS 6 you will need the following code in the modal view controller to support the landscape orientation:
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscape;
}
- (BOOL) shouldAutorotate {
return YES;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationLandscapeLeft;
}
Also, make sure you are testing on the actual device as opposed to the simulator because auto-rotation behaves differently on the simulator.
That will do the trick:
CGAffineTransform transform = CGAffineTransformIdentity;
webView.transform = CGAffineTransformRotate(transform,-M_PI/2);
OK. First of all, the question I had posted was not clear. My question was that, when I load a webview, in portrait, it was loading the webview elements in landscape mode(CSS), and was getting loaded as portrait mode(CSS) in landscape orientation.
Turns out that I was not applying the correct CSS style.
The fix I did was:
In ViewDidLoad and willAnimateRotation method, I am posting a notification to my javascript to update the style based on orientation :)
Is this possible? How might I accomplish this?
Not possible according to Apple Docs.
The word possible may need an asterisk by it. It certainly looks like Apple didn't envision (or want) you doing this. But, depending on what your requirements are, there may be a workaround.
Disclaimer: this is kind of a hack. I'm not claiming this to be a good UI, just trying to show Eli what's possible.
I built an example, starting with the Xcode template for building a Tabbed Application. It has two view controllers: FirstViewController and SecondViewController. I decided to make FirstViewController the landscape-only view. In Interface Builder (Xcode UI design mode), I set the orientation of the FirstViewController's view to landscape, and made its size 480 wide by 251 high (I'm assuming iPhone/iPod here).
Solution
Now, what seems to be necessary is to have all the tab bar's view controllers claim to support autorotation to portrait and landscape. For example:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
So, both my view controllers have that same code. However, what I do in FirstViewController is to also override willAnimateToInterfaceOrientation:duration: and essentially undo what the UIViewController infrastructure does, just for this one landscape-only view controller.
FirstViewController.m:
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration {
[super willAnimateRotationToInterfaceOrientation:interfaceOrientation duration:duration];
CGAffineTransform viewRotation;
CGRect frame;
if (UIInterfaceOrientationIsLandscape(interfaceOrientation)) {
viewRotation = CGAffineTransformIdentity;
// TODO: change to dynamically account for status bar and tab bar height
frame = CGRectMake(0, 0, 480, 320 - 20 - 49);
} else {
viewRotation = CGAffineTransformMakeRotation(M_PI_2);
// TODO: change to dynamically account for status bar and tab bar height
frame = CGRectMake(0, 0, 320, 480 - 20 - 49);
}
// undo the rotation that UIViewController wants to do, for this view heirarchy
[UIView beginAnimations:#"unrotation" context: NULL];
[UIView setAnimationDuration: duration];
self.view.transform = viewRotation;
self.view.frame = frame;
[UIView commitAnimations];
}
What you get with this is that the tab bar will always rotate with the device. That's probably a requirement, to get your dual orientation views (e.g. SecondViewController) to do autorotation. But, the actual view content of FirstViewController now does not rotate. It stays in landscape orientation, no matter how the user turns the device. So, maybe that's partially good enough for you?
Also of note:
1) I changed the app's info plist file to set the initial orientation to landscape (since my FirstViewController was the landscape one):
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIInterfaceOrientation</key>
<string>UIInterfaceOrientationLandscapeRight</string>
2) In FirstViewController.xib, I set the main/parent UIView to not Autoresize Subviews. Depending on your view hierarchy, you may want to change this property in other child views, too. You can experiment with that setting.
Now, the available size for your landscape view does change a little bit, as the status bar and tab bar are rotated. So, you may need to adjust your layout a little bit. But, basically, you will still get a wide view for showing landscape content, no matter how the user holds their device.
Results
Watch Youtube demo of running app
Not possible according to Apple Docs. All UIViewControllers must support the same orientations for any to be rotatable.
See this document (scroll down to the section titled "Tab Bar Controllers and Rotation":
http://developer.apple.com/library/ios/#documentation/WindowsViews/Conceptual/ViewControllerCatalog/Chapters/TabBarControllers.html#//apple_ref/doc/uid/TP40011313-CH3-SW1
My application contains a Tab Bar Controller and Navigation controller.
Its totally in Portrait mode. Now I have a table view in 2nd tab, clicking on each row of table view will push another view controller which will show a graphical chart, now I want this chart to be in landscape mode where as the rest of application is in portrait mode.
I came to know that we have to rotate the view on our own, now my question is how to rotate this new view in landscape mode. I put some UIView animations in viewWillAppear function, but I want the block-based animation to rotate this view to landscape for me and when I go back it rotate back portrait mode.
Thanks in advance !
Check the device orientation and make the rotation depends on it:
[UIView animateWithDuration:0.5f animations:^{ myView.transform = CGAffineTransformMakeRotation(-M_PI * 0.5); } ];
Is there any good way to set UIImagePicker to landscape orientation? I tried to call setStatusBarOrientation after presentModalViewController like following,
[self presentModalViewController:picker animated:YES];
[[UIApplication sharedApplication] setStatusBarOrientation: UIInterfaceOrientationLandscapeRight animated: NO ];
However, the video duration view (00:00) on the right corner didn't rotate as orientation changed.
Unfortunately, according to the documentation, the image picker only supports portrait mode.
Apple doesn't support landscape for camera view. If you want anything shown as customised then add overlay view on it & transform that view to look as landscape view.
#Note:-overlay is also add as portrait thats why transformation needed.
I was able to create landscape camera view using the following code:
[self.view insertSubview:self.imagePicker.view atIndex:0];
self.imagePicker.view.transform =
CGAffineTransformScale (
CGAffineTransformTranslate(
CGAffineTransformMakeRotation(M_PI/2), -90, -15),
1.2,1.2)
;
Note that I am directly adding the imagePicker's view to the current view, not calling it as a modal.
self.imagePicker.view.transform seems to respond as expected to all CGAffineTransform function calls, though I can't speak to whether or not Apple approves of this method.
Is it possible to auto-rotate the default application image according to current landscape mode? I can rotate my views just fine according to information from the UIDevice class, but I would like the whole application to be in the correct landscape mode from the start.
This isn't possible at the moment. If your app is designed to be in landscape mode you can obviously rotate your Default image but there is no way to show a different image or rotate it based on the orientation when your app launches.
Update
Updated after comments...
A trick you can use:
Use a portrait default.png
On launch load the default.png in a UIImageView and perform the rotation yourself.
UIImageview *myImage = [UIImageView alloc] initWithImage:[UIImage imageNamed:#"default.png"]]];
[UIView beginAnimations:#"rotate" context:nil]
[UIView setAnimationDelay:0.25];
[UIView setAnimationDuration:duration];
//rotation transform logic
[UIView commitAnimations];
You can rotate it to where left or right according to your setup. Then fade in your UI with another animation block.
Original answer
This kind of doesn't make sense. There isn't a need to rotate the graphic.
If you launch in landscape, then simply create your launch graphic in landscape (using photoshop or something similar).
If you think sometimes the phone will be in landscape and sometimes it won't during launch, that's not really an issue. The HIGs instruct you to simply display a view in the correct orientation if it only supports that orientation. Example: The Youtube app automatically goes to landscape to show a video and back to portrait to show the table view. You shouldn't compensate for what your user may be doing prior to launch.
This is now possible in Xcode 4.0 here is a downloadable application doing specifically doing that.