IPhone 3, iPhone 4, and iPad orientation handling - iphone

I have a view with a tableView and a mapView. In portrait mode, I want the mapView to occupy the top 60% of the screen, and the table view, the bottom 40%. In landscape, I want the mapView to occupy 45% of the screen on the right, and the tableView 55% on the left.
Thus, I thought that something like this ought to work:
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
UIScreen* mainscr = [UIScreen mainScreen];
CGSize screenSize = mainscr.currentMode.size;
if(self.interfaceOrientation == UIInterfaceOrientationLandscapeLeft
|| self.interfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
tableview.frame = CGRectMake(0, 0 , (screenSize.height*.55), screenSize.width);
mapView.frame = CGRectMake((screenSize.height*.55), 0, (screenSize.height*.45), screenSize.width);
}
else
{
tableview.frame = CGRectMake(0, (screenSize.height*.6) ,screenSize.width, (screenSize.height*.4));
mapView.frame = CGRectMake(0, 0,screenSize.width, (screenSize.height*.6));
}
}
This code works fine on the iphone simulator with version 4 of the OS, but when I try to run it on the iphone 4 simulator or the ipad simulator, the views are completely off (i can only see the about a quarter of the map in portrait and none of the table, and in landscape i can see only the table).
I dont understand why this is the case -- since im simply scaling the views to match the screen size, shouldnt something like the above code work fine regardless of the resolution of the device? I was able to make a 'fix' by scaling using different values for the iphone, iphone 4, and ipad, but the numbers that I used were discovered by trial and error, and they dont appear to make much sense.
can someone please point me towards the correct method for handing these orientation changes for all devices? Thanks so much!

I have done something similar to this. Here is how I would accomplish what you would like to do
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
CGSize screenSize = self.view.bounds.size;
[UIView beginAnimations:#"InterfaceRotations" context:nil];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:duration];
if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft || toInterfaceOrientation == UIInterfaceOrientationLandscapeRight) {
tableview.frame = CGRectMake(0, 0 , (screenSize.height*.55), screenSize.width);
mapView.frame = CGRectMake((screenSize.height*.55), 0, (screenSize.height*.45), screenSize.width);
} else {
tableview.frame = CGRectMake(0, (screenSize.height*.6) ,screenSize.width, (screenSize.height*.4));
mapView.frame = CGRectMake(0, 0,screenSize.width, (screenSize.height*.6));
}
[UIView commitAnimations];
}

Related

Toolbar disappearing when loading page upside down

So this will almost certainly be a simple answer, but I can't for the life of me work it out!
Basically, I want my current app to be viewable in portrait only (for now at least) and either the right way up, or upside down. Everything works fine the right way up and when you rotate the iPad on a page, everything works fine, the page flips up as normal. But if you hold the iPad upside down (home button at the top) and click a button to load a new page, when the page loads the toolbar is not visible! I don't know if for some reason the toolbar is behind the rest of the content or if its not there. If you then rotate the iPad back to portrait, the toolbar appears and all is back to normal again!
Whats weirder is that on the iPhone, the toolbar is there when you load a page with an upside down iPhone!!
I've tried all sorts with the shouldAutorotateToInterfaceOrientation() and didRotateFromInterfaceOrientation() methods and with resizing/positioning on viewDidLoad depending on the orientation. But nothing seems to work at all!!
This is code I have in my viewDidLoad() method:
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
NSLog(#"iPhone");
if ([[UIDevice currentDevice] orientation] == UIInterfaceOrientationPortrait)
{
self.view.frame = CGRectMake(0, 0, 320, 460);
}
else if ([[UIDevice currentDevice] orientation] == UIInterfaceOrientationPortraitUpsideDown)
{
self.view.frame = CGRectMake(0, 20, 320, 460);
}
}
else
{
NSLog(#"iPad");
if ([[UIDevice currentDevice] orientation] == UIInterfaceOrientationPortrait)
{
self.view.frame = CGRectMake(0, 0, 768, 1024);
NSLog(#"iPad Portrait Up");
}
else if ([[UIDevice currentDevice] orientation] == UIInterfaceOrientationPortraitUpsideDown)
{
self.view.frame = CGRectMake(0, 20, 768, 1024);
NSLog(#"iPad Portrait Upside Down");
}
}
I've tried similar things in the didRotateFromInterfaceOrientation() method but nothing is working!
Thanks in advance for any help and feel free to ask questions/request more code
Matt
I ran into similar problem and here is what I discovered. When You add a toolbar at the top of the iPad UIView xib file, its autosizing is default to set up as shown in figure below. The toolbar will always stick to the bottom instead of the top.
What I did is change it to stick to top as shown in figure below and it fixed my problem.
If you setup the toolbar programmatically, you need to update the autoresizingMask.

UIImage/UIView Doesn't Adjust Properly To UIInterfaceLandscape Views

I am writing an app that I would like to only be viewed in Landscape Mode. I have set it up so that if the iPhone is held in Portrait Mode, nothing happens and the current image remains in Landscape Mode. The iPhone Simulator starts out in Landscape Mode with the Home Button on the right. If the iPhone is rotated from one Landscape Mode to the other, animation then occurs and the view is adjusted. However, whenever the device is in Landscape Mode with the Home Button on the left, the image is 20 pixels higher than needed, revealing a white line at the bottom of the screen.
In spite of all attempts to logically adjust this such as
self.view.frame = CGRectMake (0,20, self.view.frame.size.width, self.view.frame.size.height)
it doesn't fix the problem. I am accounting for the Status Bar in my calculations.
The .xib file contains an UIImageView on top of a UIView. This is my first experience implementing these methods so I apologize if the solution is relatively easy. Below is the code for the two methods used to implement the Landscape Mode views.
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
//set up interface to only be viewed in Landscape
if(interfaceOrientation == UIInterfaceOrientationLandscapeLeft)
return interfaceOrientation;
else if(interfaceOrientation == UIInterfaceOrientationLandscapeRight)
return interfaceOrientation;
else
return NO;
}
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)tointerfaceOrientation duration:(NSTimeInterval)duration {
if(UIInterfaceOrientationLandscapeRight){
self.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
}
else if (UIInterfaceOrientationLandscapeLeft) {
//shouldn't adjustment to 20 fix the view?
self.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
}
else return;
}
For UIViews to adjust the subviews properly you will have to take a look at this UIView property: autoresizingMask, and set the mask to autoresize what is needed, if that does not work you will have to override:
- (void)layoutSubviews
From the reference: UIView reference

iPhone: app with only landscape and only portrait views

I am building an application with multiple UIViewControllers controlled by a RootViewController. Currently in the plist the application defaults to LandscapeRight.
Lets say I have the following files that can be loaded into the RootViewController:
IntroView (Landscape Right ONLY)
LandscapeView (Landscape Right ONLY)
PortraitView (Portrait ONLY)
I also added into the RootViewController's shouldAutorotateToInterfaceOrientation the following:
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
if ([currentClass class] == PortraitView.class) {
return (interfaceOrientation == UIInterfaceOrientationPortrait);
} else {
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
}
so all is well until I load in the PortraitView and in the viewWillAppear i add the following (similar to this thread
if (self.interfaceOrientation == UIInterfaceOrientationPortrait) { //UIInterfaceOrientationLandscapeRight) {
self.view.transform = CGAffineTransformIdentity;
self.view.transform = CGAffineTransformMakeRotation(degreesToRadian(-90));
self.view.bounds = CGRectMake(0.0, 0.0, 320, 480);
self.view.center = CGPointMake(240.0f, 160.0f);
}
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait];
This yields a properly loaded in PortraitView but now my issue is that within my PortraitView I have 2 subviews that I would like to flip between, but because I rotated my view UIViewAnimationTransitionFlipFromLeft actually makes it flip top to bottom instead of left to right. I cannot for the life of me figure out how to tell PortraitView that its in Portrait.
When I check [[UIDevice currentDevice] orientation]; it tells me its in Landscape. When I attempt to use shouldAutorotateToInterfaceOrientation and set it to Portrait only it will then rotate my view so it is no longer correct.
Hopefully this makes sense! Been looking at this issue all day.
Thanks!
I ran into this slightly differently; a UIViewController subclass in landscape mode that swapped top-to-bottom instead of left-to-right.
The fix that worked for me was to add all my views to a single “inner” view and then flip that instead of the UIViewController’s normal view.
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight
forView:[self innerView]
cache:YES];
Where [self innerView] is the sole child of [self view], and all the subviews are inside of it.

iPad SDK, how to handle orientation with an UIImageView

I'm developing an app for iPad and I try to handle multiple orientation.
My app contains a webview and a loading UIImageView that appears when my webview is loading content.
This UIImageView has a background image that I set in InterfaceBuilder. When I change orientation to landscape, the image is cut.
I'd like the UIImageView to set image-portrait.png when the ipad is in portrait mode and image-landscape.png when it's in landscape mode.
Thank you for your help and advices!
Screenshots :
I found a solution :
In Interface Builder, I set the autosizing of my ImageView to auto fill the screen.
In my ViewController, I add a method to detect the change of orientation and I set the appropriate image depending if the iPad is in portrait or landscape :
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
if((self.interfaceOrientation == UIDeviceOrientationLandscapeLeft) || (self.interfaceOrientation == UIDeviceOrientationLandscapeRight)){
myImageView.image = [UIImage imageNamed:#"image-landscape.png"];
} else if((self.interfaceOrientation == UIDeviceOrientationPortrait) || (self.interfaceOrientation == UIDeviceOrientationPortraitUpsideDown)){
myImageView.image = [UIImage imageNamed:#"image-portrait.png"];
} }
It took me awhile to understand this concept. I didn't want to create the same image portrait and landscape. The key here is that CGAffineTransformMakeRotation rotates from the original state of your UIImageView or any UIView for that matter. This assumes your background image has orientation to it. E.g. You want your UIImageView to stay put, while other objects behaves to normal orientation change event.
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
duration:(NSTimeInterval)duration {
if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) {
backgroundImage.transform = CGAffineTransformMakeRotation(M_PI / 2);
}
else if (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight){
backgroundImage.transform = CGAffineTransformMakeRotation(-M_PI / 2);
}
else {
backgroundImage.transform = CGAffineTransformMakeRotation(0.0);
}
}
You can handle the orientation by autoresizing the view.
UIImageView *imageView=[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"background-image"]];
imageView.frame = self.view.bounds;
imageView.autoresizingMask=UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight
iimageView.contentMode = UIViewContentModeScaleAspectFill;
[self.view addSubview:imageView];
[self.view sendSubviewToBack:imageView];
[imageView release];
This will be make solution to your problem.
While Salah your answer looks ok to me i believe you can do two improvements here:
Set the background image within this function:
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
duration (NSTimeInterval)duration
if you do the change within the didRotateFromInterfaceOrientation
you will change the background image once you have finished to
rotate the IPad and the transition from the two background image
won't be smooth: you will clearly see the new background image popup
at the end of the rotation.
Improve setting the myImageView.image value:
_myImageView.image = UIInterfaceOrientationIsLandscape(interfaceOrientation) ? [UIImage
imageNamed:#"image-landscape.png"] : [UIImage
imageNamed:#"image-portrait.png"];
I'd actually add another branch to docchang's code as when the iPad is rotated to portrait upside own it uses the portrait right-side-up image which can look a little odd.
I added,
if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft)
{
imageBackgroundView.transform = CGAffineTransformMakeRotation(M_PI / 2);
}
else
if (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
imageBackgroundView.transform = CGAffineTransformMakeRotation(-M_PI / 2);
}
else
if (toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)
{
imageBackgroundView.transform = CGAffineTransformMakeRotation(M_PI);
}
else
{
imageBackgroundView.transform = CGAffineTransformMakeRotation(0);
}
It is interesting that programmers have such a tough time thinking outside the box (literally in this case).
Try this (how I solved this myself).
Create a square image.
Set the constraints of the uiimageview to fill in the screen (leading, trailing, top, bottom)
Set the mode to aspect fill (which will enlarge the image, but keep its aspect ratio constant)
Done.
The key here is, of course, that you should create a square image (which is, as I said above, outside the box ;-)

How to keep image from autorotating?

I've got an UIImageView as a background image for my application, which, like a helicopter in distress, autorotates. The problem is when the orientation autorotates my image gets shifted all over the place and I don't like it. Since it's a simple texture I figure the user would prefer to have it stay in its place, and not autorotate. What I mean by this is that I would like the image to stay full screen, and when the user rotates the phone the image is just rotated 90 degrees so it appears the image is static with the phone, not the rest of the application.
You can try implementing the willAnimateRotationToInterfaceOrientation:duration: method in your view controller and rotating the UIImageView in the opposite direction.
The code below is from the top of my head, I can't guarantee that it will work:
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration {
CGFloat angle = M_PI/2; // Figure out the proper angle
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:duration];
imageview.transform = CGAffineTransformMakeRotation(angle);
[UIView commitAnimations];
}
I suggest to rotate your image in an image-editing-software and load it dynamically. This is far, far easier to do, than messing around with the angles (and also the code is easier to read).
Like this:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
if (toInterfaceOrientation == UIInterfaceOrientationPortrait || toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
myBackground.image = [UIImage imageNamed:#"bg.jpg"];
} else { // landscape view
myBackground.image = [UIImage imageNamed:#"bg_landscape.jpg"];
}
}