i have got 2 GUIs and 2 Controllers
1 is called landscapeguicontroller and the second is called highguicontroller.
Now generally i call the highguicontroller, and when i rotate my iphone it detects that and then it shows the landscapeguicontroller:
Code:
landscapeguicontroller *neu =[[landscapeguicontroller alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:neu animated:YES];
[self dismissModalViewControllerAnimated:YES];
The Problem is that then the animation pushes the new window from the beyond side of the iphone up into the window.
In the Landscapeguicontroller,i have added to the the following lines:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
when i want go back to the highguicontroller i call:
[self dismissModalViewControllerAnimated:YES];
that all works , but just in the second animation i see the correct "rotation animation".
Have you got any suggestions?
So a short Problem description:
in the 1. animation from high to landscape, the landscape is pushed into the window
BUT in the 2. animation from landscape to high, the rotation looks like a real rotation...
i want the 1.animation look like the 2. animation
best regards
Ploetzeneder
To avoid "The Problem is that then the animation pushes the new window from the beyond side of the iphone up into the window.", try setting the view controller's modalTransitionStyle property to one of the following, whatever you prefer:
typedef enum {
UIModalTransitionStyleCoverVertical = 0,
UIModalTransitionStyleFlipHorizontal,
UIModalTransitionStyleCrossDissolve,
} UIModalTransitionStyle;
Also, if you want to avoid the animated rotation, you can set your shouldRotate... method to disallow other orientations, but then set up to receive notifications when the device physically changes orientations, and present your modal viewcontroller when in the appropriate orientation for it. See Apple's "AlternateViews" sample code for an example of this.
The notifications reflect the physical orientation of the device, and you can receive them whether the interface is allowed to change or not. (You can look at the UIApplications's statusBarOrientation property to see what orientation the UI is in).
It sounds like you want the sequence to go like this:
Physically rotate the device from portrait to landscape
Animate the portrait view (highguicontroller) to landscape
Push the landscape view (landscapeguicontroller) up from the new "bottom" of the screen
If that's right, you'll need to have something like the following in your highguicontroller implementation:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown;
}
This will take care of step 2 (it will rotate the portrait view to landscape in either direction).
Then you'll want something like this:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
if(fromInterfaceOrientation == UIInterfaceOrientationPortrait) {
[self presentModalViewController:landscapeguicontroller animated:YES];
}
else {
[self dismissModalViewControllerAnimated:YES];
}
}
That should present the landscape view after the rotation animation is complete and then dismiss it after the device is rotated back to portrait.
Hope that helps!
Related
In my spritekit game has more than one level. Some of the level are in landscape mode and some of are in portrait mode. Since the first level is in the landscape mode so when I call the first SKScene I set up the viewcontroller as
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscapeRight;
}
But when I want load my second scene which would be in portrait mode it shows in landscape mode. Now how do I change the orientation from landscape to portrait in the second level. There is only one view controller in my game.
Thanks in advanced.
I don't think it is possible to change the orientation of the device from code.
You could tell the users to rotate their device for the next (or current) level and handle accordingly.
Make sure your application supports multiple orientations and in the new scene, where you want to use portrait add the following code:
- (BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
I hope this helps.
My application supports all orientations except PortraitUpsideDown.
In my view hierarchy I have an AVCaptureVideoPreviewLayer as a sublayer in the top view which is UIImageView. Then below it in view hierarchy are several overlay views showing controls.
Overlay views are working properly with orientation changes, but I don't how to be with this AVCaptureVideoPreviewLayer. I want it to behave like in Camera app, so that previewLayer stays still and controls are smoothly reorganized. Right now since the main view is rotated on orientation change, my preview layer is also rotated, which means that in landscape view it stays in portrait view, taking only part of the screen and the picture from camera being also rotated by 90 degrees. I've managed to rotate the preview layer manually, but then it has this orientation change animation, which leads to the background being seen for a while during the animation.
So what is the proper way to autorotate the controls while making previewLayer stay still?
In my implementation I have subclassed the UIView for my view which I want to rotate and something like viewController for this view which is just a subclass of NSObject.
In this viewController I do all the the checks related to changes of orientation, make decision if I should change orientation of my target view, and if yes, then I call method of my view for changing its orientation.
First of all we need to fix the orientation of whole application interface to Portrait mode, so that our ACCaptureVideoPreviewLayer always stays still.
This is done in the MainViewController.h:
(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation`
{
return interfaceOrientation==UIInterfaceOrientationPortrait;
}
It returns NO to all orientations except Portrait.
In order to our custom viewController be able to track the changes of device orientation we need to make it an observer of corresponding notifications:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(orientationChanged) name:UIDeviceOrientationDidChangeNotification object:nil];
I put these lines in the (void)awakeFromNib method of my viewController.
So each time the device orientation is changed, the viewController's method orientationChanged will be called.
Its purpose is to check what is the new orientation of device, what was the last orientation of device and decide if to change it. Here is the implementation:
if(UIInterfaceOrientationPortraitUpsideDown==[UIDevice currentDevice].orientation ||
lastOrientation==(UIInterfaceOrientation)[UIDevice currentDevice].orientation)
return;
[[UIApplication sharedApplication]setStatusBarOrientation:[UIDevice currentDevice].orientation animated:NO];
lastOrientation=[UIApplication sharedApplication].statusBarOrientation;
[resultView orientationChanged];
If the orientation is the same as before or in PortraitUpsideDown then do nothing.
Else it sets the status bar orientation to the proper one, so that when there is an incoming call or ossification, it will appear on the proper side of the screen. And then I call also method in the target view where all the corresponding changes for new orientation are done, like rotating, resizing, moving the other elements of interface in this view corresponding to the new orientation.
Here is the implementation of the orientationChanged in target view:
Float32 angle=0.f;
UIInterfaceOrientation orientation=[UIApplication sharedApplication].statusBarOrientation;
switch (orientation) {
case UIInterfaceOrientationLandscapeLeft:
angle=-90.f*M_PI/180.f;
break;
case UIInterfaceOrientationLandscapeRight:
angle=90.f*M_PI/180.f;
break;
default: angle=0.f;
break;
}
if(angle==0 && CGAffineTransformIsIdentity(self.transform)) return;
CGAffineTransform transform=CGAffineTransformMakeRotation(angle);
[UIView beginAnimations:#"rotateView" context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
[UIView setAnimationDuration:0.35f];
self.transform=transform;
[UIView commitAnimations];
Of course here you can add any other changes like translation, scaling of different views of your interface that need to respond to new orientation and animate them.
Also you may not need the viewController for this, but do all just in the class of your view.
Hope that the general idea is clear.
Also don't forget to stop getting notification for orientation changes when you don't need them like:
[[NSNotificationCenter defaultCenter]removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
[[UIDevice currentDevice]endGeneratingDeviceOrientationNotifications];
iOS 8 solution:
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft) {
self.layer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeLeft;
} else {
self.layer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
}
}
in your setup code:
self.layer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session];
self.layer.videoGravity = AVLayerVideoGravityResizeAspectFill;
if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft) {
self.layer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeLeft;
} else {
self.layer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
}
THe main problem is that when I get the notification, the statusbar has not yet rotated, so checking the current value give in fact the value before the rotation. So I added a little delay (here 2 seconds) before calling the method that check the statusbarorientation and rotates my subview :
-(void) handleNotification:(NSNotification *) notification
{
(void) [NSTimer scheduledTimerWithTimeInterval:(2.0)
target:self
selector:#selector(orientationChanged)
userInfo:nil
repeats:NO ] ;
}
The rest of the code is the one from BartoNaz.
I have a table view with some words, and i present flash-card style landscape view when the device rotates. I made it by observing the "UIDeviceOrientationDidChangeNotification".
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(openLandscapeMode) name:#"UIDeviceOrientationDidChangeNotification" object:nil];
1)That works fine and smooth, but the problem is that when the we are in the landscape, i don't want the viewcontroller to react to the spinning around the vertical axis,so that i could lay the phone on the table and it would still be in the landscape.
Maybe i should somehow observe the horizontall spinnings, instead of deviceorientation?
-(void)openLandscapeMode
{
if([[UIDevice currentDevice]orientation]==UIDeviceOrientationLandscapeLeft||[[UIDevice currentDevice]orientation]==UIDeviceOrientationLandscapeRight)
{
LandscapeCardViewController *landscape = [[LandscapeCardViewController alloc]init];
landscape.words = words;
landscape.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:landscape animated:YES];
NSLog(#"Switch to %#",[[NSUserDefaults standardUserDefaults]valueForKey:#"ChosenWordInCard"]);
[landscape release];
}
else
{
[self dismissModalViewControllerAnimated:YES];
[[UIApplication sharedApplication]setStatusBarOrientation:UIInterfaceOrientationPortrait];
}
}
2)The second question is where to remove observer, if this controller is in a tab bar, and i want to perform the same transition in another controller in the same tabbar,but,of course,with another landscape view?
I tried in viewWillDissappear, but it doesn't work properly.
Thanks a lot!
For your first question, there should be a method in your viewcontroller which you may need to edit to only support portrait
-(BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation {
return UIInterfaceOrientationPortrait(interfaceOrientation); //only allow portrait
}
That will stop it auto rotating to landscape, while keeping your original method intact
For the second. What about when the transition is complete? Then re-add it when the view appears again. And then in your landscape controller, add it to re-detect when the device is portrait.
I found the solution
I changed else to if([[UIDevice currentDevice]orientation]==UIDeviceOrientationPortrait||[[UIDevice currentDevice]orientation]==UIDeviceOrientationPortraitUpsideDown) and everything works fine!
Strange, but it works!
About removing the observer - i do it in -viewWillAppear,checking,if i am not in landscape now.
i stuck on a problem that drives me crazy!
I have an iPad application starting with a TabBarViewController. Every Tab has it's own ViewController and nib-file.
To make interface orientation possible I added all orientations to my info.plist and subclassing my TabBarController to set:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
Every View is autoresized and formatted well for displaying the right Orientation if I rotate the Interface. If I test it in the simulator, everything looks fine and I can rotate between the Orientations.
Now the point that drives me crazy:
If I launch the App in Portrait Mode, all works fine.. but if I launch in Landscape, I get an error and my Interface orientation seems still to be Portrait, while the Simulator is in Landscape Mode!!
The Error:
2011-05-24 21:50:15.011 Project[57995:207] Using two-stage rotation animation. To use the smoother single-stage animation, this application must remove two-stage method implementations.
I checked for Orientation like this:
-(void)viewWillAppear:(BOOL)animated{
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if ((orientation == UIInterfaceOrientationLandscapeLeft) || (orientation == UIInterfaceOrientationLandscapeRight)) {
NSLog(#"Orientation: Landscape");
}
else{
NSLog(#"Orientation: Portrait");
}
}
The Log says it is in "Landscape" Mode if I launch in Landscape, but if I change tab to another it looks terrible because the View is displayed in Portrait mode instead.
On change back to the start-view where i asked for Orientation… the log displays "Portrait"… but the Simulator is still Landscape!
I can't figure out why the Orientation is Portrait on start,…
even if I start in Landscape…
Any idea how to solve this problem?
Ok. So the documentation says viewWillAppear: is called prior to all animations. And when your app starts, its initial orientation is Portrait. Based on what your orientation is, it then rotates to that orientation. Since it animates to the orientation off screen, this must be called after viewWillAppear:/ So when viewWillAppear: is called, its still in Portrait. I tested this myself.
I solved the problem!
Simply used this in viewWillAppear method of all my Views, to make it work when started in Landscape mode:
if(([[UIApplication sharedApplication]statusBarOrientation] == UIInterfaceOrientationLandscapeLeft) || ([[UIApplication sharedApplication]statusBarOrientation] == UIInterfaceOrientationLandscapeRight)){
//Landscape View
}
else{
//Portrait View
}
Works fine for me!
Ok I have an interesting issue on an iPad application I am developing.
When the app launches in portrait mode the layout works as expected. I rotate the iPad and the rotation works fine.
When the application launches in landscape mode there is additional white space appearing and the layout does not work as expected. But when I rotate the application to portrait it rotates just fine. It also lays out fine when I rotate it back to landscape.
What could be causing this problem? The view controller in question is a view controller that contains a UINavigationController (I had to add in a header). I wonder if it is something with UINavigationController.
Your view is expecting Portrait mode upon launch. In your view Controller, you need to let it know to look for orientation, and load the corresponding view.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
if(((interfaceOrientation == UIInterfaceOrientationLandscapeLeft) ||
(interfaceOrientation == UIInterfaceOrientationLandscapeRight))){
self.view = landscape;
}else if(((interfaceOrientation == UIInterfaceOrientationPortrait) ||
(interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown))){
self.view = portrait;
}
return YES;
}
Ok so what was strange in my application is that the layout would become correct when the tab controller switched tabs back to the view that was being funky. So, I added a hack in order to switch between the tabs before the makeKeyAndVisible of the main window.
I did try your suggestion WrightsCS. The real reason it didn't work is because I'm loading UINavigationController's view in the sub view of the page, so I didn't really have control of the layout that was messing up. The top bar of the navigation controller was loading a little lower than it should have been.