Trying to understand how shouldAutorotateToInterfaceOrientation and UIDeviceOrientationDidChangeNotification - iphone

I have an interface that I want to startup in landscape orientation. After startup when the user rotates the device to portrait I am displaying a day view calendar. When returning to landscape orientation the calendar is dismissed. Everything works great in every orientation with my application user interface displaying properly in landscape orientation and the calendar displaying properly in portrait orientation.
The problem is if the user is holding the iPhone in landscape orientation on startup. No matter what I do I cannot get it to startup with my user interface in landscape mode. My UIDeviceOrientationDidChangeNotification method fires twice, the first time [UIDevice currentDevice].orientation is landscape, the second in it is portrait. The end result is the the user interface rotates to portrait mode and displays the day view. Not what I want. I want the user interface to stay in landscape orientation until the user physically rotates the device from landscape to portrait.
I don't understand why it fires with a landscape [UIDevice currentDevice].orientation when the user is holding the device in portrait orientation.
Here is what my code looks like in the viewController...
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
if ((interfaceOrientation == UIDeviceOrientationPortrait)|| (interfaceOrientation == UIDeviceOrientationPortraitUpsideDown)) {
return NO;
}
return YES;
}
- (void)viewDidLoad {
[super viewDidLoad];
showingCalendar = NO;
initializing=YES;
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(didRotate:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
}
-(void)didRotate:(NSNotification *)notification {
UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
if ((deviceOrientation == UIDeviceOrientationPortrait) || (deviceOrientation == UIDeviceOrientationPortraitUpsideDown)) {
if ((!showingCalendar) && (!initializing)) {
showingCalendar = YES;
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:YES];
GCCalendarPortraitView *calendar = [[[GCCalendarPortraitView alloc] init] autorelease];
navigationController = [[UINavigationController alloc] initWithRootViewController:calendar];
[self presentModalViewController:navigationController animated:YES];
}
}else if ((deviceOrientation == UIDeviceOrientationLandscapeRight) || (deviceOrientation == UIDeviceOrientationLandscapeLeft)) {
if (showingCalendar) {
showingCalendar = NO;
if (deviceOrientation == UIDeviceOrientationLandscapeRight){
[self dismissModalViewControllerAnimated:YES];
}else if (deviceOrientation == UIDeviceOrientationLandscapeLeft){
[self dismissModalViewControllerAnimated:YES];
}
}else {
initializing = NO;
}
}
}

I found a workaround to my problem. In viewDidLoad I started a scheduledTimerWithTimeInterval and moved beginGeneratingDeviceOrientationNotifications to the selector method.
Now the notification never fires more than once. The user gets landscape at startup no matter which way the device is being held and after startup all the rotations work perfectly.
Here is my modified code. Everything else stayed the same...
- (void)viewDidLoad {
[super viewDidLoad];
showingCalendar = NO;
initializing=YES;
timer = [NSTimer scheduledTimerWithTimeInterval:.55 target:self selector:#selector(startOrientationNotifications) userInfo:nil repeats: NO];
}
-(void)startOrientationNotifications {
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(didRotate:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
}

i wouldn't generate a beginGeneratingDeviceOrientationNotifications,
a simple way could be to use a BOOL to check when portrait is allowed in
shouldAutorotateToInterfaceOrientation
something like this:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
if ((interfaceOrientation == UIDeviceOrientationPortrait)|| (interfaceOrientation == UIDeviceOrientationPortraitUpsideDown)) {
return portraitIsAllowed;
}
return YES;
}
then just change it when needed in other methods .
And keep in mind that shouldAutorotateToInterfaceOrientation is called every time user rotate device AND also when you load (instantiate) your controller the first time

Related

iPad orientation not being returned correctly

I'm basically running this code:
UIInterfaceOrientation statusBarOrientation = [[UIApplication sharedApplication] statusBarOrientation];
if(statusBarOrientation == UIInterfaceOrientationPortrait){
NSLog(#"orientation is portrait");
}
However, regardless of the actual orientation in the simulator or my iPad, it is printing "orientation is portrait". Trying to NSLog the statusBarOrientation as a %d also returns 1 no matter what the orientation.
I've stuck this is my app delegate, my view controller, and the class that I need it in, and its the same thing. All 4 device orientations are supported in my info.plist / target settings.
Does anyone have a sure fire way of figuring out the interface orientation, or why mine is not working? Thanks
if you dont like to used Notification for orientation.. Then use below method too.
this is example of Only Landscape Orientation in iPad and Portrait in iPhone...
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
if(interfaceOrientation==UIInterfaceOrientationLandscapeLeft ||
interfaceOrientation==UIInterfaceOrientationLandscapeLeft)
return YES;
else
return NO;
}
else
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
}
You can REGISTER FOR notifications on orientation changes:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(didRotate:)
name:#"UIDeviceOrientationDidChangeNotification"
object:nil];
- (void)didRotate:(NSNotification *)notification
{
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if ((orientation == UIDeviceOrientationLandscapeLeft || orientation == UIDeviceOrientationLandscapeRight)) {
// DO STUFF
}
else if (orientation == UIDeviceOrientationPortrait) {
//DO MORE STUFF
}
}
Currently you are returning the orientation of the status bar. Instead get the orientation of the device: [[UIDevice currentDevice] orientation]

IOS rotate device without rotation animation

What would be the correct way to achieve an effect similar to the one in the standard iPod app of the iPhone - when the device is rotated to landscape mode, the view changes to cover flow, but the type of transition is fade and not the rotating screen?
This is how I am loading the modal view:
- (void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) {
carouselView.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:carouselView animated:YES];
}
}
Thanks!
Andrius
I later found that it is more stable to use this solution:
In the parent view controller (in my case it is tab view controller) viewdidload method add this:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didRotate:) name:#"UIDeviceOrientationDidChangeNotification" object:nil];
and then add this method:
- (void) didRotate:(NSNotification *)notification {
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if (UIInterfaceOrientationIsLandscape(orientation) && !self.modalViewController) {
[self presentModalViewController:carouselView animated:YES];
[Globals sharedGlobals].startedAtLandscape = YES;
}
if (UIInterfaceOrientationIsPortrait(orientation) && self.modalViewController) {
[self dismissModalViewControllerAnimated:YES];
[Globals sharedGlobals].startedAtLandscape = NO;
}
}
And finally if you want to prevent the rotation animation, modify this method like this:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if(UIInterfaceOrientationIsLandscape(interfaceOrientation)) {
return NO;
}
return YES;
}

iPad back button stops working on rotate

I am developing a iphone/ipad app.
Problem is that when i change the orientation of ipad portrait to Landscape, back button of navigation controller stops working.
It"s work fine when orientation not changed.
i am using this code
- (BOOL) isPad{
#ifdef UI_USER_INTERFACE_IDIOM
return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);
#else
return NO;
#endif
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
if ([self isPad]) {
return YES;
}
else
{
return UIInterfaceOrientationIsPortrait(interfaceOrientation);
}
}
What"s the wrong with this code?
This will work :
-(void)viewWillAppear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receivedRotate:) name:UIDeviceOrientationDidChangeNotification object:nil];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
}
-(void)viewWillDisappear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
}
Now implement the following method :
-(void)checkOrientation
{
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if (orientation == UIDeviceOrientationLandscapeLeft||orientation==UIDeviceOrientationLandscapeRight)
{
// Set x coorinate of views you want to change
}
else
{
// Set x coordinates of views to initial x xoordinates.
}
}
Create recievedRotate :
- (void)receivedRotate:(NSNotification *)notification
{
[self checkOrientation];
}
In viewDidLoad :
-(void)viewDidLoad
{
// Code
[self checkOrientation];
}
My guess is that your button is out of the view's frame and thus won't receive touch events. I think something is wrong with the way your app redraws on orientation change.

iPhone device orientation problem

My application is Navigation based.
All views are displaying Portrait mode except Report mode.Report mode display landscape mode when device is rotate landscape.
If device is rotate landscape mode Report view is displaying landscape mode.if report is landscape mode once again rotate in device Portrait mode it will display normal view of current view.
Flow of current action my view display.
From current view is Portrait mode and i am rotating device in landscape mode so getting Landscape mode of Report mode. after two rotate only i am getting current view in Portrait mode. I need to reduce tow rotation . please guide me . How to check condition for after landscape mode of Report if once again rotate i need to display current view in Portrait mode.
Here at ReportViewController
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return UIInterfaceOrientationIsLandscape(interfaceOrientation);
}
#interface CurrentViewController
BOOL isShowingLandscapeView;
Report *landscapeViewController;
#implementation CurrentViewController
- (void)viewDidLoad
{
[super viewDidLoad];
Report *viewController = [[Report alloc]initWithNibName:#"Report" bundle:nil];
self.landscapeViewController = viewController;
[viewController release];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(orientationChanged:)
name:UIDeviceOrientationDidChangeNotification object:nil];
}
- (void)orientationChanged:(NSNotification *)notification
{
[self performSelector:#selector(updateLandscapeView) withObject:nil afterDelay:0];
}
- (void)updateLandscapeView
{
UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
if (UIDeviceOrientationIsLandscape(deviceOrientation) && !isShowingLandscapeView)
{
[self presentModalViewController:self.landscapeViewController animated:YES];
isShowingLandscapeView = YES;
}
else if(deviceOrientation == UIInterfaceOrientationPortrait && isShowingLandscapeView)
{
[self dismissModalViewControllerAnimated:YES];
isShowingLandscapeView = NO;
}
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait ); // support only portrait
}
I'm not sure I understand your question, but the code looks like it might have the logic reversed.
In the ReportViewController,
- (BOOL)shouldAutorotateToInterfaceOrientation
is called before the rotation, so it should
return YES for Portrait (YES, allow the view to rotate from Landscape TO portrait)
and return NO for Landscape (NO, do not allow the view to rotate to Landscape from Landscape).
And similarly in CurrentVC - try
return (interfaceOriention==UIInterfaceOrientationLandscape);
Hope that helps.
-Mike

Change View on only one Tab in Tabbar-Application (Landscape-Portrait)?

How can I change the view when rotating the iphone (change nib's).
But it should only happens in one single tab!
I tried it with:
- (void)viewDidLoad {
LandscapeViewController *viewController = [[LandscapeViewController alloc]
initWithNibName:#"LandscapeView" bundle:nil];
self.landscapeViewController = viewController;
[viewController release];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(orientationChanged:)
name:UIDeviceOrientationDidChangeNotification object:nil]; }
- (void)orientationChanged:(NSNotification *)notification
{
[self performSelector:#selector(updateLandscapeView) withObject:nil afterDelay:0];
}
- (void)updateLandscapeView
{
UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
if (UIDeviceOrientationIsLandscape(deviceOrientation) && !isShowingLandscapeView)
{
[self presentModalViewController:self.landscapeViewController animated:YES];
isShowingLandscapeView = YES;
}
else if (deviceOrientation == UIDeviceOrientationPortrait && isShowingLandscapeView)
{
[self dismissModalViewControllerAnimated:YES];
isShowingLandscapeView = NO;
}
}
But then the Landscape-View appears in all Tabs. (When this code is loaded once).
Any idea?
What's happening is your view controller is receiving the UIDeviceOrientationDidChangeNotification notification whenever the rotation changes, whether or not it is being displayed. Instead try using the built-in methods of UIViewController that are meant for responding to rotations.
http://tinyurl.com/ycb8of2
This is from Apple's Docs (View Controller Programming Guide):
Tab Bar Controllers and View Rotation
Tab bar controllers support a portrait
orientation by default and do not
rotate to a landscape orientation
unless all of the root view
controllers support such an
orientation. When a device orientation
change occurs, the tab bar controller
queries its array of view controllers.
If any one of them does not support
the orientation, the tab bar
controller does not change its
orientation.
So, I'm not sure that the Tab Bar Controller is designed to rotate just for a single view.
Tanks for your comments!
I found a workaround:
//Remove Observer if not in Landscape
- (void)viewDidDisappear:(BOOL)animated {
if (isShowingLandscapeView == NO) {
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
}
}
//Add Observer if not in Landscape
- (void)viewDidAppear:(BOOL)animated {
if (isShowingLandscapeView == NO) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
}
}