Changing UIView on orientation change - objective-c

Hey all. I have a fairly simple question. I am developing a "rich" iPad app, and I have two background images specifically designed for landscape and portrait. I'd like this ImageView to automatically change depending on the devices orientation. (like pretty much all of Apples iPad apps).
Can anyone point me in the right direction? I'm assuming it would be something I do on viewDidLoad..

The best thing you can do is to change the frames of your subview frames according to your interface orientations. You can do it like:
#pragma mark -
#pragma mark InterfaceOrientationMethods
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (UIInterfaceOrientationIsPortrait(interfaceOrientation) || UIInterfaceOrientationIsLandscape(interfaceOrientation));
}
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
if(UIInterfaceOrientationIsPortrait(toInterfaceOrientation)){
//self.view = portraitView;
[self changeTheViewToPortrait:YES andDuration:duration];
}
else if(UIInterfaceOrientationIsLandscape(toInterfaceOrientation)){
//self.view = landscapeView;
[self changeTheViewToPortrait:NO andDuration:duration];
}
}
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------
- (void) changeTheViewToPortrait:(BOOL)portrait andDuration:(NSTimeInterval)duration{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:duration];
if(portrait){
//change the view and subview frames for the portrait view
}
else{
//change the view and subview frames for the landscape view
}
[UIView commitAnimations];
}
Hope this helps.

I actually figured out a very simple alternative way around this. Since I am just changing the background image, adding this..
`
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation) interfaceOrientation duration:(NSTimeInterval)duration {
if (interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation ==
UIInterfaceOrientationPortraitUpsideDown) {
[brownBackground setImage:[UIImage imageNamed:#"Portrait_Background.png"]];
} else {
[brownBackground setImage:[UIImage imageNamed:#"Landscape_Background.png"]];
}
}
`
Changes the background of a declared UIImageView based on orientation. Only downside is, the current background image is not visible in Interface builder as it is handled with code.

One small addition to Madhup's approach, which is great. I found I needed to add this to viewDidLoad to set initial background image for portrait or landscape:
// set background image
if (self.interfaceOrientation == UIInterfaceOrientationPortrait || self.interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"portraitBG.png"]];
} else {
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"landscapeBG.png"]];
}
thanks again Madhup

You can encapsulate this entirely in your UIView by watching whether bounds.width > bounds.height
This may be desirable if you're writing a small, self aware control.
class MyView: UIView {
override func layoutSubviews() {
super.layoutSubviews()
if bounds.height > bounds.width {
println("PORTRAIT. some bounds-impacting event happened")
} else {
println("LANDSCAPE")
}
}
}

Related

Reset frames when rotating orientation

I have an app that has some buttons and a text view and a label. I want to rotate the device and have them redrawn on the screen to fit. I want to do it programatically. Currently I have these methods:
-(void)willRotateToInterfaceOrientation:
(UIInterfaceOrientation)toInterfaceOrientation
duration:(NSTimeInterval)duration {
[super willRotateToInterfaceOrientation:toInterfaceOrientation
duration:duration];
if (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight ||
toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) {
[self reOrderSideways];
} else {
[self reOrderUpDown];
}
}
-(void)reOrderSideways{
self.viewLabel.frame=CGRectMake(175.0,140.0,130.0,20.0);
self.buttonOne.frame=CGRectMake(20.0,20.0,440.0,100.0);
self.buttonTwo.frame=CGRectMake(20.0,180.0,440.0,100.0);
self.textContent.frame=CGRectMake(20.0, 290.0, 440.0, 100.0);
self.theScroller.contentSize = CGSizeMake(480.0, 350.0);
}
-(void)reOrderUpDown{
self.viewLabel.frame=CGRectMake(95.0,15.0,130.0,20.0);
self.buttonOne.frame=CGRectMake(20.0,50.0,280.0,190.0);
self.buttonTwo.frame=CGRectMake(20.0,250.0,280.0,190.0);
self.textContent.frame=CGRectMake(20.0, 450.0, 280.0, 190.0);
self.theScroller.contentSize = CGSizeMake(320.0, 460.0);
}
It doesn't quite work because when i rotate sideways, the buttons and labels and textview get cutoff the right side. I checked it and it looks like its using the coordinates I gave it but it is still using the portrait frame or bounds. How can i fix this?
Try using willAnimateRotationToInterfaceOrientation: instead.

Objective C: Orientation Change With UIScrollview

I am trying to make an app with UIScrollView (pagingEnabled) that should adapt on the device's interface orientation.
to do this, i made two UIScrollViews loaded with UIImageviews and UIButtons inside and animations (CA). one for portrait and the other one for landscape (you'll see it in my code).
now my problem is whenever i rotate the device, yes! it respond to the orientation change but it goes back to the first page.
ok picture this... you are already on the 10th page of the scrollView in portrait then when you switched to landscape it is on the first page again.
i hope explained it clearly.
and... it crashes on iPad when i rotate it.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown || interfaceOrientation == UIInterfaceOrientationLandscapeRight || interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
if(toInterfaceOrientation == UIInterfaceOrientationPortrait || toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown){
//self.view = portraitView;
[self changeTheViewToPortrait:YES andDuration:duration];
}
else if(toInterfaceOrientation == UIInterfaceOrientationLandscapeRight || toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft){
//self.view = landscapeView;
[self changeTheViewToPortrait:NO andDuration:duration];
}
}
- (void) changeTheViewToPortrait:(BOOL)portrait andDuration:(NSTimeInterval)duration{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:duration];
if(portrait){
//change the view and subview frames for the portrait view
[self forPortrait];
[self removeMainSVLContents];
}
else{
//change the view and subview frames for the landscape view
[self forLandscape];
[self removeMainSVPContents];
}
[UIView commitAnimations];
}
What's inside "forPortrait" is the same as in "forLandscape" they just have different frames and it has different images too that will fit the screen on portrait and landscape.
at the time of the animation use **scrollRectToVisible:animated:** method to show or stay on the desire place of scroll view
may this will be useful to you.

Manual Rotation Method Breaks with Side Switch

Currently I'm workign on a drawing app for the iPad. I need to reposition and rotate the toolbar in the app when it is put into a different orientation while keeping the the drawing area in the same place.
I found a method here for doing this. It uses the NSNotificationCenter to monitor for rotation changes. This calls a custom didRotate: method that will rotate and reposition my toolbar based on the UIDeviceOrientation.
This part works fine. However, whenever the side switch on the iPad is engaged to lock the orientation, the toolbar repositions to the location is was at launch.
For example: If I start the application in landscape left and rotate it to portrait, the toolbar will reposition to the bottom of the screen. However as soon as I engage the slide switch, it moves to the side of the screen for the landscape left orientation.
The methods I'm using for this are all below.
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didRotate:) name:UIDeviceOrientationDidChangeNotification object:nil];
}
- (void)didRotate:(NSNotification *)notification {
UIDeviceOrientation deviceOrientation = [[UIDevice currentDevice] orientation];
UIInterfaceOrientation interfaceOrientation;
bool orientationFound = YES;
if (deviceOrientation == UIDeviceOrientationPortrait) {
interfaceOrientation = UIInterfaceOrientationPortrait;
} else if (deviceOrientation == UIDeviceOrientationPortraitUpsideDown) {
interfaceOrientation = UIInterfaceOrientationPortraitUpsideDown;
} else if (deviceOrientation == UIDeviceOrientationLandscapeLeft) {
interfaceOrientation = UIInterfaceOrientationLandscapeRight;
} else if (deviceOrientation == UIDeviceOrientationLandscapeRight) {
interfaceOrientation = UIInterfaceOrientationLandscapeLeft;
} else {
orientationFound = NO;
}
if (orientationFound) {
[self.toolbar changeToOrientation:interfaceOrientation withDuration:.25];
[self.tutorialOverlay changeToOrientation:interfaceOrientation];
}
}
- (void)changeToOrientation:(UIInterfaceOrientation)orientation withDuration:(float)duration {
float angle;
CGPoint origin;
if (orientation == UIInterfaceOrientationPortrait) {
angle = portraitAngle;
origin = self.portraitOrigin;
} else if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
angle = portraitUpsideDownAngle;
origin = self.portraitUpsideDownOrigin;
} else if (orientation == UIInterfaceOrientationLandscapeLeft) {
angle = landscapeLeftAngle;
origin = self.landscapeLeftOrigin;
} else if (orientation == UIInterfaceOrientationLandscapeRight) {
angle = landscapeRightAngle;
origin = self.landscapeRightOrigin;
}
[UIView animateWithDuration:duration animations:^{
self.transform = CGAffineTransformMakeRotation(angle);
CGRect rect = self.frame;
rect.origin = origin;
self.frame = rect;
}];
}
I'd strongly recommend against using this notification-based approach. Note that the name of the notification is UIDeviceOrientationDidChangeNotification; the device orientation is not the same as the interface orientation, and it leads to lots of little issues like this. (The device orientation, for example, includes UIDeviceOrientationFaceDown, which is never associated with an interface orientation.)
I'd suggest letting your view controller automatically rotate itself; this will place the toolbar, etc, for you. You can then override - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration to put the drawing area back to the orientation you want to maintain. (You'd use similar code to your changeToOrientation method above, but for the drawing area instead, and you don't need to create your own animation block. Also, the angles would all be negated, because you're undoing the change the view controller made.)
I just answered a similar question here.
Basically just allow the interface to rotate, but rotate the view you don't want to rotate 'back' in willRotateToInterfaceOrientation:duration:.

iPhone force orientation

First - I read all similar topics and non of them work for me.
I have few View Controllers. And I change them by that code:
- (void)flipToAzbukaMenu {
AzbukaMenuController *aAzbukaMenu = [[AzbukaMenuController alloc] initWithNibName:#"AzbukaMenu" bundle:nil];
[self setAzbukaMenuController:aAzbukaMenu];
[aAzbukaMenu release];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:2.0];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlDown forView:window cache:NO];
[viewController.view removeFromSuperview];
[azbukaArcadeController.view removeFromSuperview];
[self.window addSubview:[azbukaMenuController view]];
[UIView commitAnimations];
}
Also I have proper key in plist that allows me to start the application in landscape mode. When the app starts it has proper orientation (landscape), but when I change my view it becomes portrait and becomes again landscape only after rotating device 270 degree (not 90 lol). How do I force the app to show all views in landscape mode?
UPD:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
if ((interfaceOrientation==UIInterfaceOrientationPortrait)||(interfaceOrientation==UIInterfaceOrientationPortraitUpsideDown))
{
return NO;
}
if ((interfaceOrientation==UIInterfaceOrientationLandscapeLeft)||(interfaceOrientation==UIInterfaceOrientationLandscapeRight))
{
return YES;
} else {
return YES;
}
}
There are two landscape modes and two portrait modes. One is landscape left, the other is landscape right. For instance, if you flip to one of the portrait modes (let's say, with home button on the bottom) from landscape left, you are going to get a 270 degree rotation.
As for how to force your views to stay in landscape (pick one of the two modes), just do something like:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}
This will always cause that view to be displayed in landscape left orientation.

iPhone SDK: Orientation (Landscape and Portrait views)

Okay, I've got my normal app which is in portrait mode. I can force my app to go to landscape mode for a view (using navigationcontroller and viewcontroller) like this:
- (void)viewWillAppear:(BOOL)animated {
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];
}
But then when I go back to the main menu (tableview) it goes straight back to portrait. I try this code:
- (void)viewWillAppear:(BOOL)animated {
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait];
}
But that doesn't work..
Any ideas?
Take a look at the function shouldAutorotateToInterfaceOrientation: in the UIViewController class. This function returns YES if the orientations are supported by your UIView. If you return YES only to the landscape orientation, the iPhone will automatically be put in that orientation.
The following code should do it. Put it in the UIViewController that controls the view that you want to put in landscape mode.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationLandscape);
}
To get this to work, I added this to the rootviewcontroller:
- (void)viewWillAppear:(BOOL)animated {
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait];
}
This seems to be working now.
Here's what I'm doing to do this:
first, put this define at the top of your file, right under your #imports:
#define degreesToRadian(x) (M_PI * (x) / 180.0)
then, in the viewWillAppear: method
[[UIApplication sharedApplication] setStatusBarHidden:YES animated:NO];
if (self.interfaceOrientation == UIInterfaceOrientationPortrait) {
self.view.transform = CGAffineTransformIdentity;
self.view.transform = CGAffineTransformMakeRotation(degreesToRadian(90));
self.view.bounds = CGRectMake(0.0, 0.0, 480, 320);
}
if you want that to be animated, then you can wrap the whole thing in an animation block, like so:
[UIView beginAnimations:#"View Flip" context:nil];
[UIView setAnimationDuration:1.25];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[[UIApplication sharedApplication] setStatusBarHidden:YES animated:NO];
if (self.interfaceOrientation == UIInterfaceOrientationPortrait) {
self.view.transform = CGAffineTransformIdentity;
self.view.transform = CGAffineTransformMakeRotation(degreesToRadian(90));
self.view.bounds = CGRectMake(0.0, 0.0, 480, 320);
}
[UIView commitAnimations];
Then, in your portrait mode controller, you can do the reverse - check to see if its currently in landscape, and if so, rotate it back to Portrait.
You need to edit your Info.plist file to add the UIInterfaceOrientation key with the appropriate value (UIInterfaceOrientationLandscapeRight or UIInterfaceOrientationLandscapeLeft).
You can't use this private API.
There is a solution to do that : it's to use a view controller and adding its view to the window. then in that controller you force landscape in the shouldAutorotate... methode. It works fine, but be sure it's necessary for your project to use that, because it's not very smart  to force the user to turn his iPhone. By the way, here is an example code if you need it.
http://www.geckogeek.fr/iphone-forcer-le-mode-landscape-ou-portrait-en-cours-dexecution.html