I have a universal application created in storyboard mode. It is set-up to automatically rotate to the current orientation. I have attempted to disable some orientations in iPhone-mode but it does not work when I test in the simulator.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
return ((interfaceOrientation != UIInterfaceOrientationLandscapeRight) || (interfaceOrientation != UIInterfaceOrientationLandscapeLeft));
} else {
return YES;
}
}
Also, when the iPad is rotated, it should go through the following code BUT all I get is a black screen.
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
if (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight) {
self.view = landscape;
self.view.transform = CGAffineTransformMakeRotation(deg2rad*(90));
self.view.bounds = CGRectMake(0.0, 0.0, 1024.0, 748.0);
} else if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) {
self.view = landscape;
self.view.transform = CGAffineTransformMakeRotation(deg2rad*(-90));
self.view.bounds = CGRectMake(0.0, 0.0, 1024.0, 748.0);
} else {
self.view = portrait;
self.view.transform = CGAffineTransformMakeRotation(0);
self.view.bounds = CGRectMake(0.0, 0.0, 768.0, 1004.0);
}
} else {
}
}
Why are all these problems arising here? I have tried the code in different Xcode projects without storyboards ad it works fine. What is going on and how can I fix this?
You should create two separate stackoverflow questions. I will answer your first question here.
Consider this line from your code:
return ((interfaceOrientation != UIInterfaceOrientationLandscapeRight) || (interfaceOrientation != UIInterfaceOrientationLandscapeLeft));
If the orientation is Right, then your code reduces to return (Right != Right) || (Right != Left), which always returns true.
If the orientation is Left, then your code reduces to return (Left != Right) || (Left != Left), which always returns true.
If the orientation is Up, then your code reduces to return (Up != Right) || (Up != Left), which always returns true.
If the orientation is Down, then your code reduces to return (Down != Right) || (Down != Left), which always returns true.
It's not clear which orientations you want to allow and which you want to exclude. If you want to allow only portrait orientations, do this:
return UIInterfaceOrientationIsPortrait(interfaceOrientation);
If you want to allow only landscape orientations, do this:
return UIInterfaceOrientationIsLandscape(interfaceOrientation);
Related
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.
I have a splitViewController. This is in Detail VC
-(void)viewDidLoad
{
self.masterIsVisible = YES;
//a botton in navigation bar to hide or show the master view.
[button addTarget:self action:#selector(showOrHideMasterView)
forControlEventsTouchUpInside]
//gesture control to swipe right or left to slide master view in and out.
[swiperight addTarget:self action:#selector(showMasterView)];
[swipLeft addTarget:self action:#selector(hideMasterView)];
}
-(void)showOrHideMasterView
{
if (self.masterIsVisible)
[self hidemasterView]; self.masterIsVisible = NO;
else
[self showMasterView]; self.masterIsVisible = YES;
}
-(void)hideMasterView
{
//hides master view by substracting masterview's width from its origin.x
}
-(void)showMasterView
{
//shows master View by adding masterview's width to its origin.x
}
- (BOOL)splitViewController:(UISplitViewController *)svc shouldHideViewController: (UIViewController *)vc inOrientation:(UIInterfaceOrientation)orientation
{
return NO;
}
Everything almost works as intended.
Problem: In one orientation && master is NOT visible.. then device changes orientation.. the master View instead of sliding off the screen pushed the detail view the other way. I know thats because the flag now is set as masterIsVisible = NO instead of YES. What can I do to change the flag to YES on device rotation. looks trivial but cant seem to figure out.
I tried registering for devicechnagenotification in UIDevice but that did not work. The BOOL is YES in any Orientation. The apple example uses this but looks like thats not the right approach here.
Ok, I finally figured out to set the flag correctly for orientation change. I added the following method
-(void)willAnimateRotationToInterfaceOrientation:
(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
if (toInterfaceOrientation == UIInterfaceOrientationPortrait)
self.masterIsVisible = NO;
else if (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)
self.masterIsVisible = YES;
else if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft)
self.masterIsVisible = YES;
else if (toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)
self.masterIsVisible = NO;
}
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:.
I'm developing this application on the iPad. My MainWindow contains a Split View Controller which loads the RootViewController and DetailViewController.
I have this image that is placed at the bottom-right of the DetailViewController.
My application allows different orientations, therefore i want the image to appear at different positions for different orientations.
This is my code in DetailViewController:
- (void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
if(toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft || toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
myImage.frame = CGRectMake(183.0f, 257.0f, 548.0f, 447.0f);
}
else if(toInterfaceOrientation == UIInterfaceOrientationPortrait || toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)
{
myImage.frame = CGRectMake(244.0f, 518.0f, 548.0f, 447.0f);
}
}
When i launch my application and my iPad is at portrait orientation, the image will be correctly placed at (X:244, Y:518) which is at the bottom right.
But when i launch my application and my iPad is at landscape orientation, the image will not be shown and i suspect that it is still at the position for portrait orientation. Only when i rotate my iPad to portrait orientation and then back to landscape orientation, then the image will appear at (X:183, Y:257) which is correct.
What i tried to do is to place these codes in my DetailViewController's 'viewWillAppear' method:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if(self.interfaceOrientation == UIInterfaceOrientationLandscapeLeft || self.interfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
myImage.frame = CGRectMake(183.0f, 257.0f, 548.0f, 447.0f);
}
else if(self.interfaceOrientation == UIInterfaceOrientationPortrait || self.interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)
{
myImage.frame = CGRectMake(244.0f, 518.0f, 548.0f, 447.0f);
}
}
But when i launch my application, it still has the same problem.
What can i do so that when i first launch my application in landscape orientation, it will be correctly placed at (X:244, Y:518) ?
You might want to try putting your resizing logic in didRotateFromInterfaceOrientation instead of willRotateToInterfaceOrientation.
My custom layout code only worked when I called it after the rotation had completed it, rather than before.
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
NSLog(#"didRotateFromInterfaceOrientation");
float width;
float height;
if ((fromInterfaceOrientation == UIInterfaceOrientationLandscapeRight) ||
(fromInterfaceOrientation == UIInterfaceOrientationLandscapeLeft))
{
width = [[UIScreen mainScreen] applicationFrame].size.width;
height = [[UIScreen mainScreen] applicationFrame].size.height;
NSLog(#"Changing to portrait: %f x %f", width, height);
}
else
{
width = [[UIScreen mainScreen] applicationFrame].size.height;
height = [[UIScreen mainScreen] applicationFrame].size.width;
NSLog(#"Changing to landscape: %f x %f", width, height);
}
NSLog(#"Changed orientation: %f x %f", width, height);
// Call my custom layout function to setFrame on all my UI controls
[self doLayout:width height:height];
[super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
}
If your app shows the status bar then you probably need to call self.view.frame.size.width instead of getting the size from the applicationFrame.
Make sure that you're overriding
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation; // Override to allow rotation. Default returns YES only for UIInterfaceOrientationPortrait
To return YES for each UIInterfaceOrentation that you want to support, otherwise willRotateToInterfaceOrientation and didRotateToInterfaceOrientation wont get called.
Try calling this early in your applicationDidFinishLauching:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
Since the detailViewController wouldn't sometimes know its orientation, I solved this issue by having a shared variable in the appDelegate that would store the device orientation throughout the app. You can initialize it in the splitViewController with its orientation so when the detailViewController loads it can read it from there.
I have a ScrollView with a Custom View. Now i have the problem with the rotation, the view has after the rotation not the correct frame pos / size.
How can i call the CustomView after rotation for a reposition and resize the frame and content?!
- (void)setupPage
{
NSUInteger nimages = 0;
CGFloat cx = 0;
for (; ; nimages++) {
if (nimages == list.count) {
break;
}
CustomStepView *stepView = [[CustomStepView alloc] initWithFrame:CGRectZero];
stepView.tag = nimages;
if([[UIDevice currentDevice] orientation] == UIDeviceOrientationPortrait || [[UIDevice currentDevice] orientation] == UIDeviceOrientationPortraitUpsideDown)
{
stepView.frame = CGRectMake(cx, 0.0 , 768.0f, 926.0f);
cx += 768.0;
}
else
{
stepView.frame = CGRectMake(cx, 0.0 , 1024.0f, 670.0f);
cx += 1024.0;
}
[scrollView addSubview:stepView];
[stepView release];
}
self.pageControl.numberOfPages = nimages;
}
From what it looks like, You have a lot of subviews(Custom Views) in your ScrollView.
First of all never try to detect the orientation using UIDevice , it is not recommended by apple.
For handling rotations you have been provided with the function : "shouldAutorotateToInterfaceOrientation"
Inside this method, You can simple run a loop for detecting the subviews present inside your scrollview and then set the frame and size of each subview.
This might look something like this:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if(interfaceOrientation == UIInterfaceOrientationPortrait)
{
for(UIView *asubview in scrollView.subviews)
{
asubview.frame = "NEW FRAME";
}
}
else
{
asubview.frame = "NEW FRAME";
}
}
Hope it helps you..although i know this has been asked long back :-)
Cheers