I have 2 screens: the first screen support all orientations, the 2nd screen just support landscape right orientation.
I want the first screen to save its orientation before pushing to the second screen and return to that orientation when it pops back from the second screen.
my code:
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[UIDevice currentDevice] setValue:#(currentOrientaion) forKey:#"orientation"];
[UIViewController attemptRotationToDeviceOrientation];
}
it's work but sometime screen rotates many time to change orientation.
Someone help me: why is that?
You should call these lines in some other method like ViewDidLoad because
for a specific view controller, viewWillAppear method may call multiple times.
Related
In my app, I do not intend to show the status bar. So, my app covers the whole screen view. I could manage doing it inserting the
- (BOOL) prefersStatusBarHidden{
return YES;
}
method in my main viewController and also adding to my app delegate
if ([self respondsToSelector:#selector(setNeedsStatusBarAppearanceUpdate)]) {
// iOS 7
[self performSelector:#selector(setNeedsStatusBarAppearanceUpdate)];
} else {
// iOS 6
[application setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide];
}
This all works well when I open the app in the portrait mode. However, when opened in the landscape mode, while the status bar gets hidden, I see a black band of background image on top of my view. Indeed my view is vertically offset by the height of status bar height (see picture below).
This does not happen if I open the app first in portrait mode and then rotate. So, I am doing something wrong in the initialization of the view frame I thought, which I do by the usual
CGRect screenRect = [[UIScreen mainScreen] applicationFrame];
[self.view setFrame:screenRect];
Any suggestions on this would be really appreciated.
Thanks in advance,
Nikhil
I seem to have fixed the issue (at least for now). I did not fix in the info-plist the options
I hate this. To do one single setting one has to add so many things, that too in different places: one in the appDelegate, other in the main view controller and yet another completely outside the code :(.
I've got a SplitView Controller for iPad, which should display a Calculator which I made in portrait mode, and a Graph calculator when rotated into landscape mode.
This is what my storyboard looks like currently, am I doing it wrong?
I'm still new to the whole SplitView Controller concept in iOS, so I ain't sure how this whole thing works.
Currently, only the highlighted view gets displayed in both landscape and portrait mode, but I only want to display it in landscape mode, and display the calculator in portrait mode, as well as remove the option to display the Master button from portrait mode, but display it in landscape mode i.e. don't display the Master Table in landscape mode, only when the button is pressed.
Apple's SplitView Controller doesn't allow hiding the master view in landscape mode, but you could use a custom class, like this one.
For the screen-rotation part, just do a modal segue when the orientation changes.
This will notify you when the orientation changes:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(changeOrientation:) name:UIDeviceOrientationDidChangeNotification object:nil];
Then for the function
- (void) changeOrientation : (UIDeviceOrientation) orientation {
if(!UIDeviceOrientationIsValidInterfaceOrientation(orientation))
return;
if(orientation == UIDeviceOrientationLandscapeLeft || orientation == UIDeviceOrientationLandscapeRight) { // Or UIDeviceOrientationPortrait
[self performSegueWithIdentifier:#"SEGUENAME" sender:self];
}
}
More about segues: HERE
My root view controller's implementation of supportedInterfaceOrientations almost always returns UIInterfaceOrientationMaskAll, however there is one edge case where it returns UIInterfaceOrientationMaskLandscape.
This is working, if the user rotates the device. However if the device is being held in portrait mode the supportedInterfaceOrientations method does not ever get called, unless the user manually rotates the device.
How can I programatically tell the system that the return value of this method has changed?
According to the documentation, it seems like I should be able to call [UIViewController attemptRotationToDeviceOrientation] however this does not have any effect (supportedInterfaceOrientations is never called and the screen does not rotate).
I found various workarounds others have posted to try and solve this problem, but none of them work in my tests. I suspect they may have worked in iOS 5.0, but not iOS 6.0.
I am returning YES in the root view controller's shouldAutorotate method.
First of all, it might be useful if you used this if you want to present your UIViewController in Landscape mode.
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeLeft | UIInterfaceOrientationLandscapeRight;
}
Also, A lot depends on with which controller is your UIViewController embedded in.
Eg, If its inside UINavigationController, then you might need to subclass that UINavigationController to override orientation methods like this.
subclassed UINavigationController (the top viewcontroller of the hierarchy will take control of the orientation.) needs to be set it as self.window.rootViewController.
- (BOOL)shouldAutorotate
{
return self.topViewController.shouldAutorotate;
}
- (NSUInteger)supportedInterfaceOrientations
{
return self.topViewController.supportedInterfaceOrientations;
}
From iOS 6, it is given that UINavigationController won't ask its UIVIewControllers for orientation support. Hence we would need to subclass it.
Note :
The shouldAutorotate and supportedInterfaceOrientations method always get called for UINavigationController whenever Push operations are done.
Quote from Apple's UIViewController Class Reference:
Note: At launch time, apps should always set up their interface in a portrait orientation. After the application:didFinishLaunchingWithOptions: method returns, the app uses the view controller rotation mechanism described above to rotate the views to the appropriate orientation prior to showing the window.
http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html
If the interface starts in portrait the autorotation should be able to handle the adjustment even if the user opens the app with the device on its side.
Update: I found this post that should help with rotations after launch. Apparently iOS 6 looks at the navigation controller to determine supported device orientations.
How to force a UIViewController to Portrait orientation in iOS 6
You need to manually rotate it. You'll want to call the following logic in your view controller's viewWillAppear: method:
UIDeviceOrientation curDevOrientation = [[UIDevice currentDevice] orientation];
if (![self supportsOrientation:curDevOrientation]) {
// We're going to rotate 90 degrees clockwise. First figure out what that
// means to the status bar.
UIInterfaceOrientation newStatusBarOrientation;
switch (curDevOrientation) {
case UIDeviceOrientationPortrait:
newStatusBarOrientation = UIInterfaceOrientationLandscapeRight;
break;
case UIDeviceOrientationPortraitUpsideDown:
newStatusBarOrientation = UIInterfaceOrientationLandscapeLeft;
break;
}
[[UIApplication sharedApplication] setStatusBarOrientation:newStatusBarOrientation animated:NO];
// Now rotate the view 90 degrees clockwise.
CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI * 90.0 / 180.0);
self.view.transform = transform;
}
That should rotate the particular view controller's view, whenever it appears.
In iOS, what is the proper way to manually rotate your views? I have a lot of custom rotation animations and I don't want my view to autorotate at all.
Right now, I'm doing this...
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return interfaceOrientation == UIDeviceOrientationPortrait;
}
Then, I'm doing this and responding to orientation changes as needed:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
Everything is working fine, except... When I try to present action sheets, a MailViewController, etc, they all display in portrait orientation :(
How can I have my view know that, while I don't want it to autorotate, it is in fact responding to orientation notifications which I am handling manually?
Edit: To clarify, it's not that my rotations aren't working, it's that when I present a UIActionSheet, it assumes I must be in portrait (even when I've manually rotated so that I'm not), and it displays incorrectly.
Try to use [[UIApplication sharedApplication] setStatusBarOrientation:(UIInterfaceOrientation)]; when you manualy rotate your view
Maybe you can call a method from within shouldAutorotateToInterfaceOrientation.
for example:
- (BOOL)shouldAutorotateToInterfaceOrientation (UIInterfaceOrientation)interfaceOrientation
{
if (interfaceOrientation != UIDeviceOrientationPortrait)
[self theActionYouWantToPerform]
// Return YES for supported orientations
return interfaceOrientation == UIDeviceOrientationPortrait;
}
The line reported by Anton K
[[UIApplication sharedApplication] setStatusBarOrientation:(UIInterfaceOrientation)];
Works me fine!. Is IT just the element that rested me when I want to MANUALLY rotate an UIView of an UIViewController using the CGAFFineTransformMakeRotation method for rotating the view PI/2 radians.
This line, set the ORIENTATION of the STATUS BAR to the (UIInterfaceOrientation) you want, for making the perfect appearance of an UIView "manually" rotated to the (UIInterfaceOrientation) I want.
In consequence, this line also makes UIMessageView's further presented, appears it in the (UIInterfaceOrientation) you indicated.
I have a view controller and separate nib files for portrait and landscape. On rotating, I load the respective nib. The methods
shouldAutorotateToInterfaceOrientation and willRotateToInterfaceOrientation
get called and the nib does change.
The problem:
the landscape nib does not appear as landscape, but portrait! The status bar is
correctly rotated and appears on the top:
(Sorry, couldn't paste the image, because my account is new. The screenshot is in
landscape, with a landscape status bar, but a landscape view shown as portrait.)
One would think the problem lies in not setting the orientation as Landscape in IB Simulated metrics for the view, but I've done that and the view appears as landscape in IB. (I don't think it would even be possible to create a rotated button like that if the view was portrait.) Besides these two nibs I have a mainwindow.xib, which contains the app delegate, window and view controller objects.
EDIT: I realized that the views are actually rotating, when they should "stay up". It's like there's an extra transformation. When I rotate the phone 90° right, the landscape xib is displayed rotated 90° right. When I rotate the phone another 90° right, the portrait xib is displayed upside down. The status bar is always correctly displayed at the top.
EDIT2: Using
self.view.transform = CGAffineTransformMakeRotation((M_PI * (90) / 180.0));
in willRotateToInterfaceOrientation I can rotate the view to landscape left (and to any orientation I want), so I can use that as a workaround. However, I have other projects, where the view rotates automatically and doesn't require the use of CGAffineTransformMakeRotation. It's like something is preventing the automatic rotation here.
Are you adding the view loaded from nib as subView? If Only the status bar is rotating it means your previous view is hung while releasing the view and adding the new view.Can you tell how are you adding the view loaded from xib to the SuperView.
Make sure you are releasing the previous view correctly while loading the other view,put NSLOG in dealloc of the views and check whether the view is getting released completely.
I had done something similar to this only instead of making an nib file separately I just added two subviews to the main nib as prtraitView and Landscape View
and switched them as follows
In viewDidAppear method
-(void)viewDidAppear:(BOOL)animated{
if(UIDeviceOrientationIsPortrait(self.interfaceOrientation))
{
self.portraitVIew.frame=self.view.bounds;
self.portraitVIew.frame=self.view.frame;
[self.view addSubview:self.portraitVIew];
}else{
self.landscapeView.frame=self.view.frame;
[self.view addSubview:self.landscapeView];
}
self.view.autoresizesSubviews = YES;
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(deviceOrientationDidChangeNotification:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
}
and then Implemented deviceOrientationDidChangeNotification as follows
- (void)deviceOrientationDidChangeNotification:(NSNotification*)note
{
if ([[UIDevice currentDevice] userInterfaceIdiom]==UIUserInterfaceIdiomPad) {
}else{
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if(UIDeviceOrientationIsLandscape(self.interfaceOrientation))
{
self.landscapeView.hidden=NO;
self.landscapeView.frame=self.view.frame;
[self.portraitVIew removeFromSuperview];
[self.view addSubview:self.landscapeView];
}else {
self.landscapeView.hidden=YES;
self.portraitVIew.frame=self.view.frame;
NSLog(#"Portrait");
[self.view addSubview:self.portraitVIew];
}
}
}
It worked very well for me..