I have an iPad app that has 2 views each with its own View Controller. Apple states they suggest iPad apps be able to rotate in all directions. I used this technique to position the elements in my storyboard on rotation changes:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
//[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
if (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight || toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft)
{
studentNumberButton.frame = CGRectMake(30, 1, 158, 155);
studentNumberLabel.frame = CGRectMake(173, 57, 347, 43);
studentLabel.frame = CGRectMake(528, 56, 67, 43);
// Other code goes below...
I did this for each view and it works fine for all rotations. However the issue comes up when I say, have the the iPad on View Controller 1 in landscape and press a button to show View Controller 2, View Controller 2 comes up just fine but is in Portrait mode. Same happens if I am in landscape mode for View Controller 2 and go to View Controller 1. If I am in portrait mode, everything is fine for both views.
How can i make it so when I switch views, the view knows what orientation the device is in and rotates accordingly?
Thanks!
You need to add a viewWillAppear method as follows:
- (void)viewWillAppear:(BOOL)animated {
if (([self interfaceOrientation] == UIDeviceOrientationLandscapeLeft)|| ([self interfaceOrientation] == UIDeviceOrientationLandscapeRight)) {
studentNumberButton.frame = CGRectMake(30, 1, 158, 155);
studentNumberLabel.frame = CGRectMake(173, 57, 347, 43);
studentLabel.frame = CGRectMake(528, 56, 67, 43);
...
} else {
...
}
}
Related
Im using the following code to adjust the height and frame of my view when flipping landscape/portrait (to compensate for hiding status bar):
-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator{
UIInterfaceOrientation toInterfaceOrientation = (UIInterfaceOrientation)[[UIDevice currentDevice]orientation];
if((toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft || toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)&&
!UIInterfaceOrientationIsLandscape(self.interfaceOrientation)){
NSLog(#"Going LandScape");
//self.view.frame = CGRectOffset(self.view.frame, 0, -20);
self.view.frame = CGRectMake(0, -20, self.view.frame.size.width, self.view.frame.size.height+20);
}
if(toInterfaceOrientation == UIInterfaceOrientationPortrait || toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown){
NSLog(#"Going Portrait");
//self.view.frame = CGRectOffset(self.view.frame, 0, 20);
self.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height-20);
}
}
It works fine on my first view controller when loading the app. But whenever I present a new (or the same) view controller, it doesn't move up the frame when going landscape. I get the correct logs as for when going portrait or landscape, and obv I have the same code on all my view controllers. Can someone tell me whats going on? (note presenting the same view controller will still give me issues when going to landscape even though this was working initially)
EDIT:
To make things even worse, I tried adding a button in the if(landscape) statement. The button will be drawed initially, but whenever I re-present the view controller, it doesn't even draw the button. I think I'm losing my mind...
It seems that the first time i rotate to landscape, it works, no matter what VC I'm on. but then reloading any vc, will make it not work.
Solution is pretty simple in my opinion: The function viewWillTransitionToSize is getting called only after the orientations is changed so you should make helper class that will somehow manage rotation or check the orientation on view did load.
You can simply test my statement by adding breakpoint in the function.
This line of code needs to be added at start of viewWillTransitionToSize:
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
(and damn that was painful to realise what an awfully simple mistake I did (but it normally is like that:) ) .... been pulling hairs out for long with this problem)
HI I am developing an iOS Universal application for both orientation Portrait and Landscape
I am using following code for adjusting my UI according to orientation change
- (void)viewDidLoad
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(deviceOrientationDidChange:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
}
- (void)deviceOrientationDidChange:(NSNotification *)notification
{
[self changeTheOrientation];
}
- (void)changeTheOrientation
{
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
if ( UIDeviceOrientationIsPortrait(orientation))
{
//For Portrait set frame size
lblBookInfo.frame = CGRectMake (0, 20, 718, 50);
btnClose.frame = CGRectMake (718, 20, 50, 50);
}
else if (UIDeviceOrientationIsLandscape(orientation))
{
//For Landscape set frame size
lblBookInfo.frame = CGRectMake (0, 20, 974, 50);
btnClose.frame = CGRectMake (974, 20, 50, 50);
}
}
else
{
if (UIDeviceOrientationIsPortrait(orientation))
{
//For Portrait set frame size
lblBookInfo.frame = CGRectMake (0, 20, 290, 30);
btnClose.frame = CGRectMake (290, 20, 30, 30);
}
else if (UIDeviceOrientationIsLandscape(orientation))
{
//For Landscape set frame size
if ( [[UIScreen mainScreen] bounds].size.height==568 ) {
} else {
}
}
}
}
The basic code structure which I am using for handling different UI frame with change in orientation is above.
But the problem which i am facing is that the UIDeviceOrientationDidChangeNotification is not fired every time , I think it gets missed for some times , I have checked this by setting proper breakpoints , this problem makes look my Ui really bad as sometimes UI do not change accordingly to the frame.
This approach works properly for some initial UI changes but get failed after some (10-20)orientation changes.
Is it the correct approach which I am using or is there any better approach to handle different orientations in iOS
I am developing app for (iOS 6 and iOS 7).
Use the following code to detect orientation in the callback for the UIDeviceOrientationDidChangeNotification -
UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
Then to detect if it is landscape or portairt you can -
if (UIDeviceOrientationIsLandscape(deviceOrientation) {
//do landscape related view changes
} else if (UIDeviceOrientationIsPortrait(deviceOrientation) {
//do portrait related view changes
}
I have seen this line being added before registering for orientation change notifications. Usually in awakeFromNib method -
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
Then register for notifications -
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(deviceOrientationDidChange:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
I am building a template app. I am having some issues with the device rotation/orientation. I have the following in my appDelegate didFinishLaunching:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
and in my VC viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(deviceOrientationDidChange:) name:UIDeviceOrientationDidChangeNotification object:nil];
...
//add the title bar
titleBar = [[OAI_TitleBar alloc] initWithFrame:CGRectMake(0.0, 0.0, 1024.0, 50.0)];
titleBar.titleBarTitle = #"OAI Template";
titleBar.hasAccount = YES;
titleBar.hasReset = YES;
titleBar.hasHome = YES;
[titleBar buildTitleBar];
[self.view addSubview:titleBar];
This is my deviceOrientationDidChange method:
//rotate the vc view
if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation)) {
[self.view setFrame:CGRectMake(0.0, 0.0, 1024.0, 768.0)];
} else if (UIDeviceOrientationIsPortrait([UIDevice currentDevice].orientation)) {
[self.view setFrame:CGRectMake(0.0, 0.0, 768.0, 1024.0)];
}
//call the rotation management methods of various classes
[titleBar adjustForRotation:orientation];
}
This works fine when I rotate the device, the views adjust as expected. But when the app launches, the x,y coordinates are wrong - when I log the frame when launching in portrait orientation, the VC view's frame is {{0, 20}, {768, 1004}}, when launching in landscape mode it is {{20, 0}, {748, 1024}}
The titlebar frame is {{20, 0}, {748, 1024}} for landscape and portrait (which is as I coded it).
However, what I am seeing in the simulator and on my device is drastically different. What you should see is a black bar (50 pixels or so in height) at the top with a logo on the left, followed by some buttons and then the app title aligned right. As you can see from the images below, when the app launches in either orientation it's opening x/y coords are no where near 0/20. Any help would be appreciated.
What it looks like to me is that when the app launches in landscape it is being displayed as portrait and when it launches as portrait, though the display is right, it is off by about 20.0f or so. Any help would be appreciated.
Solved it, I
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation == UIInterfaceOrientationLandscapeRight;
}
in my viewController, made sure the correct orientations were in my plist and it loads fine.
I am using UIViewController for display my view. My view have been created in interface builder.
Right now these are next parameters for view:
width: 568
height: 320
Orientation: Landscape
in ViewController I have next code:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return ((interfaceOrientation == UIInterfaceOrientationLandscapeLeft) || (interfaceOrientation == UIInterfaceOrientationLandscapeRight));
}
in info.plist I have added just two interface orientation right and left.
but when I try to output width of my view in code I get 320 and when I try to output height it write down in console 568 but I expect 320 instead.
I don't know why it works like this. Any suggestions?
even if I add this:
[self.view setFrame:CGRectMake(0, 0, 568, 320)]; in viewDidLoad method. even then I have inccorect height
I need to know width size I use in this method:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
CGFloat width = 0.0f;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
width = 568.0f;
} else {
width = 1024.0f;
}
NSInteger page = scrollView.contentOffset.x / width;
NSLog(#"%d", page);
}
Right now I use hardcode variable of width, but how come. Why I can't use self.view.frame.size.width because the sides swop each other - because.
Maybe you're printing width and height in the viewDidLoad method before the orientation occurs. Try to print it on viewWillAppear or with performSelector:afterDelay:
Another thing that might affect the dimension of the view is how you set the autoresizing mask on the interface builder (the red arrows below the x,y,height,width section on the right panel)
Please add LaunchScreen.storyboard in your project and set it as your Launch Screen under
Targets > General > App Icons and Launch Images > Launch Screen file.
I've got a massive problem and I really hope you can help me here... I'm very lost at the moment :(
I've got a project that runs with a MainWindow.xib. In my app delegate file I check the orientation of the device and load an appropriate NIB file that have different layouts (subviews) based on orientation. Here is the code to check the orientation:
-(void)checkTheOrientation
{
if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeLeft || [[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeRight)
{
viewController = [[[MyViewController alloc] initWithNibName:#"MyWideViewController" bundle:nil] autorelease];
NSLog(#"Landscape = MyWideViewController");
}
else if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationPortrait || [[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationPortraitUpsideDown)
{
viewController = [[[MyViewController alloc] initWithNibName:#"MyViewController" bundle:nil] autorelease];
NSLog(#"Portrait = MyViewController");
}
}
This works as expected and in Landscape or Portrait I am loading the correct views. The portrait view loads perfectly but the Landscape view loads with a thick black edge to the left as if it's x & y positions are not set to 0 & 0 respectively.
Here is the portrait view: http://uploads.socialcode.biz/2f25352B0e3x3z2t2z21
Here is the landscape view with the bug: http://uploads.socialcode.biz/1G2k3T012d1z0Y1U2q1k
In the MyViewController.m file I have a rough fix to get the sizing done correctly to avoid this big black strip on the left. Here's the code for this:
- (void) performLayout {
// Ensure the main view is properly placed
NSInteger MaxSizeHeight, MaxSizeWidth;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
MaxSizeHeight = 1024;
MaxSizeWidth = 768;
}
if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeLeft || [[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeRight) {
CGRect mainViewFrame = [[self view] frame];
float width = mainViewFrame.size.width;
mainViewFrame.size.width = mainViewFrame.size.height;
mainViewFrame.size.height = width;
mainViewFrame.origin.x = 0;
mainViewFrame.origin.y = 0;
[[self view] setFrame:mainViewFrame];
} else {
CGRect mainViewFrame = [[self view] frame];
mainViewFrame.origin.x = MaxSizeWidth - mainViewFrame.size.width;
mainViewFrame.origin.y = MaxSizeHeight - mainViewFrame.size.height;
[[self view] setFrame:mainViewFrame];
}
// Ensure the content view is properly placed
CGRect contentFrame = [mainContentView frame];
if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeLeft || [[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeRight)
{
contentFrame.size.width = MaxSizeHeight;
contentFrame.size.height = MaxSizeWidth;
}
contentFrame.origin.x = 0;
contentFrame.origin.y = 44;
[mainContentView setFrame:contentFrame];
// Ensure the content subviews are properly placed
contentFrame.origin.y = 0;
for (UIView *contentView in [mainContentView subviews]) {
[contentView setFrame:contentFrame];
}
}
The problem with this method is that this is just a very bad hack and it's not actually solving my problem. When it loads up in Landscape it now resizes and positions the subview to 1024x768,0,0 but any additional subviews that I load via other NIBs have the same problem.
What I would really like to know is how on earth can I set the landscape main superview to be 1024x768 position 0 & 0 without having to try and hack this together and keep performing the performLayout selector? At the moment there is a lot of inconsistence with this as the hack doesn't actually set the superview sizing correctly but rather just the subviews I load on top of the superview.
I thought that maybe a simple fix like this might solve the superview issue but alas it doesn't:
window.frame = CGRectMake(0, 0, 1024, 768);
I just want my main superview to be the placed and sized correctly at load and then the superviews just load in the right place. Please can you help me here???
First, UIView has a method named -layoutSubviews that you can override to position the subviews however you like. It'll be called when the view is first loaded, and again before drawing if you ever send it a -setNeedsLayout message.
Second, you should be able to properly set these positions in your .xib or storyboard file. Select your main view in its .xib file and check its position in the Size inspector. Also, ensure that the view is set to Landscape orientation in the Attributes inspector. If it's all correct, then there's something else going on. To simplify the problem, make a new project in Xcode with nothing but an empty view in landscape orientation. I just did one, and there's no position problem. That's what you want in your real app, so figure out what's happening in your real app to affect the view's position that's not happening in your new sample app.