I have used UIDeviceOrientationDidChangeNotification to get notified of landscape and potrait mode. In my project I'm required to change the positions of UIControls placed on the UIView accordingly. Do I have to change the frame size manually for each UIControl, as this is hectic?
In your view controller you should implement method:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
This method should return YES for supported orientations.
If you want your subviews to resize and reposition automatically then you should set appropriate property autoresizingMask of that views. For example:
blackView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight |
UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin |
UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
You do need to use the shouldAutorotateToInterfaceOrientation... method but you need to do a little more before it will work properly. First of all, you will need two xib files, one for a landscape orientation and one for a portrait orientation. You will then need to use your function like this:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (interfaceOrientation == UIInterfaceOrientationLandscapeRight || interfaceOrientation == UIInterfaceOrientationLandscapeLeft){
//prepare for a Landscape view
}
else{
//prepare for a portrait view
}
return YES;
}
As for preparing for landscape or portrait views, using autoresizing can work but you may need to have totally seperate xibs. I could not find a way to change the xib within the active view controller, so I would suggest making a seperate instance of your view controller. Example:
When you present your first instance of the viewController, present it with the portrait xib. You may also need a boolean to keep track of the current xib. Then have this code implemented:
/*Assuming you are using a viewcontroller called viewController, and you have a boolean called xibPortrait.
You have presented this view controller using the portrait xib.
You also have a landscape xib, Landscape.xib
*/
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if ((interfaceOrientation == UIInterfaceOrientationLandscapeRight || interfaceOrientation == UIInterfaceOrientationLandscapeLeft) && xibPortrait){
xibPortrait = FALSE;
viewController *Land = [[ViewController alloc] initWithNibName:#"Landscape" bundle:nil];
[self presentModalViewController:Land animated:NO];
[Land release];
}
else if(!xibPortrait){
[self.parentViewController dismissModalViewControllerAnimated:NO];
xibPortrait = TRUE;
}
return YES;
}
//This should work but if you can, you should try to use Autoresizing.
EDIT:
I also found this which someone posted on one of my questions. It may help your app work more efficiently than using my method above:
http://aseriesoftubes.com/articles/ipad-development-101-orientation/
Related
I have one application in which a tab bar controller is having 3 tabs and each tab having a view controller.
View controller 1 and 2 are supporting only portrait mode but view controller in tab 3 supports all orientations -portrait, landscape left, landscape right and portrait upside down.
For tab 3, We have to show a particular view when device is in portrait mode and another view when device is in landscape mode.
If device is in portrait mode and user clicks on the tab 3, view is loaded correctly in portrait mode and then if we rotate the device to landscape mode the landscape view is loaded correctly.
But it we turn the device to landscape mode in the tab 1 itself and then click on the tab 3 , then the problem occurs then it shows the screen to be shown in landscape mode but it displays it as a portrait view.
When I tried to find out the reason for this in the delegate method by NSLogging
(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
the value of the interfaceOrientation is 1 which is UIInterfaceOrientationPortrait
and the control is going into the if condition written for the portrait mode
if(interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown){
and when I tried to print the value of UIDevice orientation in the same delegate method
UIDeviceOrientation interfaceOrientation = [UIDevice currentDevice].orientation;
NSLog(#" device orientation %u", interfaceOrientation);
the value printed in console is 4- which is UIDeviceOrientationLandscapeRight.
So the interface orientation is UIInterfaceOrientationPortrait but device orientation is UIDeviceOrientationLandscapeRight.
One more thing, now if I rotate the device to portrait mode and then moving to landscape mode shows the correct landscape view and app starts behaving correctly.
So the problem is if I load the tab 3 in landscape mode it doesn't load properly
but if we enter in portrait mode and then rotate to landscape if works fine from thereon.
If anyone can give some useful suggestion why the behavior is like this that would be really beneficial.
Thanks
Add these lines to your Tab1 & Tab2 in viewWillAppear method,
#import <objc/message.h>
- (void)viewWillAppear:(BOOL)animated {
if(UIDeviceOrientationIsLandscape(self.interfaceOrientation)){
if ([[UIDevice currentDevice] respondsToSelector:#selector(setOrientation:)]) {
objc_msgSend([UIDevice currentDevice], #selector(setOrientation:), UIInterfaceOrientationPortrait );
}
}
}
Create a CustomTabBarController Class with Subclass of UITabBarController (for e.g: CustomTabBarController)
#interface CustomTabBarController : UITabBarController
Add the following lines to this class :
- (BOOL)shouldAutorotate
{
return [self.selectedViewController shouldAutorotate];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return [self.selectedViewController shouldAutorotateToInterfaceOrientation:toInterfaceOrientation];
}
- (NSUInteger)supportedInterfaceOrientations
{
return [self.selectedViewController supportedInterfaceOrientations];
}
In your app delegate or where ever you are initializing UITabBarController, replace those instances with CustomTabBarController instances.
self.tabBarController = [[[CustomTabBarController alloc] init] autorelease];
Add the lines to your model view controllers with different view controller support:
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationMaskPortrait;
}
-(BOOL)shouldAutorotate {
return NO;
}
I have two view controller in my app.
1st view controller is portrait mode and 2nd view controller in landscape mode.
I don't want to change their orientation even when i rotate my iPhone.
How can i make?
In the Xcode, highlight the project in the Project Navigator, and select the target in the project tree. Open the Summary page, and go to the Supported Interface Orientations section. Un-click the orientations that you do not want your application to support.
In the story board, choose your first view controller, go to the Attributes inspector, and set orientation to "Portrait" in the Simulated Metrics section. Now choose the second view controller, and set its orientation to "landscape".
In the view controller code, implement
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
for the first view controller, and
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscape;
}
for the second view controller. This should fix the problem for you.
In your case you have two VCs. So in both VC under below method just handle you orientations. and perform check against toInterfaceOrientation and return YES.
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
// For your VC1
if (toInterfaceOrientation == UIInterfaceOrientationPortrait)
return YES;
// For your VC2
/*
if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft || toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)
return YES;
*/
}
I have a Table View Controller (root) and 5 View Controllers in my project. The view Controllers turn only to landscape view (as I want) but not the Table View Controller (only in the Portrait view).In supported Device Orientations I deleted Portrait and Upside down, and I wrote in every class:
(BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return ((interfaceOrientation == UIInterfaceOrientationLandscapeLeft) || (interfaceOrientation == UIInterfaceOrientationLandscapeRight));
Any suggestions to make Table view turn only to landscape view?
put this in the viewDidLoad
self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
I'm new to StackOverflow, and also new to objective-c.
I have tried looking for a couple weeks now to find something that gives me a hint of what to do, but I can't seem to get through this one without asking a question. It feels like it should be simple, but...
I'm having a problem with the rotation of a "rootView" controller. It should show up in landscape (which it did, before I decided to use a navigation controller). The simulator shows up in the correct orientation, but it has loaded the view rotated 90 degress left, so that the text reads from bottom to top, sideways, so you have to cock your head left. The leftmost portion of the view is visible, but the remainder of the view runs off the top of the screen. It's a large program (I'm finding that, in general, with objective-c, but enjoying it nonetheless...), but here's the gist of what I think are the important code areas:
In the appDelegate, I create a window, my rootViewcontroller, and the navcontroller:
// .h file:
UIWindow *window;
wordHelper3ViewController *viewController;
UINavigationController *navigationController;
Then in the implementation:
//.m file
- (BOOL)application:(UIApplication *)applicationdidFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Hide status bar
application.statusBarHidden = YES;
// --- Add the view controller's view to the window and display.
[window addSubview:viewController.view];
[window addSubview:navigationController.view];
[window makeKeyAndVisible];
return YES;
}
Then I release all of these in the dealloc.
In my root view, I'm doing this:
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
if (interfaceOrientation == UIInterfaceOrientationLandscapeRight){
return YES;
} else {
return NO;
}
}
I implemented the following, to see what was happening, and I'm getting the log message on startup immediately:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{
if (fromInterfaceOrientation == UIInterfaceOrientationLandscapeLeft || fromInterfaceOrientation == UIInterfaceOrientationLandscapeRight) {
NSLog(#"didRotate...");
}
}
Other than this, I don't think I'm doing anything in my code that should affect the view(s). So now, on to InterfaceBuilder:
In the attributes inspector for both the rootView and the navigation controller, the orientation is set to landscape. For the rootView, under referencing outlets, the “view” is set to file's owner. I also have an action attached to the view (touchUpInside) – I changed its class to UIButton, because I wanted to resignFirstResponder when the user clicks anywhere in the background.
For the navigationController, under Referencing outlets, it shows a connection from the navigationController to my appDelegate.
In the main window xib, the nav contoller shows up in the list, and the view controller shows up as a subview of it.
The viewcontroller also shows up on its own, in the main window's list of objects.
The only thing that stands out to me, is that when I double click the window object, IT comes up visually in portrait mode.
Does anyone have any ideas?
If you want the startup orientation to be different from the initial Portrait mode, you need to edit your info.plist file. Add an entry for "intial interface orientation" and set the value that you want.
Here's a screenshot:
If you want to rotate a UINavigationController, it will take a bit more work. See this similar question for more information.
I think your problem is that you are adding your navigation controller as a subview to the window and orientation notifications are only sent to the first subview in "window".
Try this instead.
//.m file
- (BOOL)application:(UIApplication *)applicationdidFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Hide status bar
application.statusBarHidden = YES;
// --- Add the view controller's view to the window and display.
[window addSubview:viewController.view];
[viewController.view addSubview:navigationController.view];
[window makeKeyAndVisible];
return YES;
}
Its annoying, but I've resolved orientation problems by only every having one subview in "window" and then controlling everything through that one subview (in this case viewController)
Forgive me if I'm misunderstanding, but shouldn't this
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
if (interfaceOrientation == UIInterfaceOrientationLandscapeRight){
return YES;
} else {
return NO;
}
}
really be this
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
?
I am working on an app (my first one), which is basically a TabBar app.
To be more precise there are:
- a login view controller
- a tab bar controller (when login is done)
- a landscape view controller that is used when the first itel of the TabBar is switch from Portrait to Landscape.
So, when I am in the first tab, I need to be able to move to landscape view to display some other data. In my tab bar controller, I have implemented those methods:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if([self selectedIndex] == 0)
return YES;
return NO;
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
// Get AppDelegate
MyAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
if (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
// Remove TabBarView and add graph Landscape View
[self.view removeFromSuperview];
[delegate setSubViewLandscapeViewController];
}
}
In the delegate, I have implemented the setSubViewLandscapeViewController and the setSubViewTabBarController:
- (void)setSubViewTabBarViewController {
[window addSubview:[tabBarController view]];
}
- (void)setSubViewGraphLandscapeViewController {
[window addSubview:[landscapeViewController view]];
}
I want the landscapeViewController to display only in landscape mode, I have then (in my landscapeViewController):
- (void)viewWillAppear:(BOOL)animated {
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];
}
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
NSLog(#"willRotateToInterfaceOrientation");
}
A part of this works fine, I mean the switch from portrait to landscape is ok (when I am in the first tab), the tabbarcontroller is remove from the SuperView and the landscape view is added as a subview instead.
The thing is... I do not know how to switch back to portrait mode (and then load the previous controller, the tabBar one using the setSubViewTabBarViewController of my delegate). It seems none of the willRotateToOrientation, willRotateFromOrientation, .. are triggered when I actually move the device from the landscape view...
In short, when I am in the landscape view I do not know what to do to move back to the tabbar view... I am kind of stuck in the landscape view once I am in this one.
Thanks a lot for your help,
Luc
Look at the pie chart in CPTestApp-iPhone in the examples folder. It handles rotation by implementing -(void)didRotateFromInterfaceOrientation: and resizing the graph after a rotation.
Well, I managed to get a solution for this problem.
In fact, while moving from portrait to landscape I removed the tabbarcontroller from window subview and add the landscapeviewcontroller instead.
It seems it was not the correct thing to do.
Instead, I add the landscapeViewController as subview of the tabbarcontroller and remove it when going from landscape to portrait.
I still have a problem however with the y position of the landscape view which seems to changes when I do several decive rotation in a row....
Regards,
Luc