UIDeviceOrientationDidChangeNotification doesn't work while device is on table? - iphone

Hi there i have a problem,
In my AppDelegate i have used method beginGeneratingDeviceOrientationNotifications to start notify me when device starts rotating.
It works fine if i hand-held my ipad but when it is kept on table it doesn't work as expected.
it fires UIDeviceOrientationUnknown notification.
Also this notification gets started after UI launches not on splash screen.
following is my code:
if([[[PulseUIFactory Factory] GetUICreator] IsIPad])
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
}
current device stars giving proper values.
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
then some where i launches my UI as
[self Launch_UI];
but notification starts responding after [self Launch_UI]; call even if notification is registered before its call...
Please any help is appreciable!!!

When you place your device on a table, [[UIDevice currentDevice] orientation] will return UIDeviceOrientationFaceUp. Then if your device remains sitting on the table face up, it doesn't matter how you rotate it on the table, the current device orientation will still be UIDeviceOrientationFaceUp.
If the device has issues determining the orientation, you may get UIDeviceOrientationUnknown. See this tutorial on how to handle device rotation using UIDeviceOrientationDidChangeNotification.
Regarding your notification only firing after the UI is loaded, the UIDeviceOrientationDidChangeNotification will only fire when the device is rotated. So if you are not rotating your device until after the UI loads, you wont get a notification. If this is not the cause of the issue, I'd have to see more of your code to have a better idea of what is going on.

Related

How to get device orientation when the screen rotation is locked?

I used the notification to get the device's orientation.
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[notificationCenter addObserver:self
selector:#selector(deviceOrientationDidChange)
name:UIDeviceOrientationDidChangeNotification
object:nil];
But the selector function is not called when the device's screen rotation is locked. Any help?
You can use accelerometer to get values of screen orientation. See this. Also see this blog

Callback method on auto rotation, iOS and iPad

I am working on iPhone game, i was curious to know if there is a call back function tht gets called when the device forces auto rotation on the game, so that i can change the HUD elements.
Or shd i run infinite loop that checks if the app has rotated in a different thread? problem is i dont think this is an effective way. Does anyone have any good solution for this.
All you have to do is this:
In your didfinishlaunching write this
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didRotate:)
name:UIDeviceOrientationDidChangeNotification object:nil];
and then copy the following callback method
- (void) didRotate:(NSNotification *)notification
{
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if (orientation == UIDeviceOrientationLandscapeLeft)
{
NSLog(#"Landscape Left!");
self.isLandscapeLeft=1;
}else if(orientation == UIDeviceOrientationLandscapeRight){
NSLog(#"Landscape Right!");
self.isLandscapeLeft=0;
}
}
Likewise you can check orientation for potrait mode,face-up,face-down,upside down and landscapeleft and landscape right orientation.:)
Yes there is, as long as the device is not orientation locked you can register to listen to
UIDeviceOrientationDidChangeNotification
which can be seen here http://developer.apple.com/library/ios/#documentation/uikit/reference/UIDevice_Class/Reference/UIDevice.html
If you want to overcome the possibility of the device being orientation locked, then you have to manually monitor the accelerometer of the device.
In a game where orientation is essential, manually monitoring is recommended, since the first method has a little delay.

Notification listeners causing crashes

I'm using the following code to detect/listen for when the iPad changes device orientation.
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(didRotate:)
name:#"UIDeviceOrientationDidChangeNotification"
object:nil];
This calls my didRotate: method when something changes. In my didRotate: method, I use UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation]; to figure out what the orientation is, and apply my code accordingly.
However, in real life testing, I noticed that didRotate: gets called every second if the iPad is in a person's hand. It appears the listener is literally listening for every little tilt and shift in the iPad, which obviously happens a lot in a person's hands (as opposed to flat on a desk).
Any ideas on how I can fix this? I could change my code to use interface orientations, but I've been having trouble with it for whatever reason. Thank you.
*UPDATE: This listener is created in my UIImageView subclass. There are about a dozen or more on the screen. I have added [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications]; to my removal methods for when I remove an instance. That helps explain why didRotate kept showing up so much (my error).
However, I have narrowed down crashes: whenever I remove this an instance of this subclass, and rotate my iPad, I crash. Sometimes I get weird messages like [__NSArrayM didRotate]: is unrecognized selector (and other wierd objects like UIPanVelocity...something). Is my listener still listening after the instance is removed?
FIXED: Thank you for your help. I finally noticed what was wrong. I was removing the instance without removing the observer and ending notifications. Adding following code into my instance removal methods fixes my problem:
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] removeObserver:self];
I'm guessing that you add observers repeatedly and never remove them. This means that the same entry point may get invoked multiple times for a single event. It also means that when the "self" object goes away you get a crash.
The notification is only sent if the device changes from one orientation to another orientation - it doesn't get fired more times than necessary.
UIDeviceOrientation has 2 more orientations than UIInterfaceOrientation. It has FaceUp and FaceDown. Possibly it is these that are getting triggered, and you're not interested in them.
typedef enum {
UIDeviceOrientationUnknown,
UIDeviceOrientationPortrait,
UIDeviceOrientationPortraitUpsideDown,
UIDeviceOrientationLandscapeLeft,
UIDeviceOrientationLandscapeRight,
UIDeviceOrientationFaceUp,
UIDeviceOrientationFaceDown
} UIDeviceOrientation;
Maybe you would prefer to listen for UIInterfaceOrientation changes in the view controller that is currently onscreen.
typedef enum {
UIInterfaceOrientationPortrait = UIDeviceOrientationPortrait,
UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,
UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight,
UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeft
} UIInterfaceOrientation;
.
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration

Which method will be called when the iOS device turn into Landscape mode?

I know that I can return YES to support Landscape mode in shouldAutorotateToInterfaceOrientation. But I would like to display a new view, when the user turn the device into landscape mode, how can I do so? thank you.
Observer this event UIDeviceOrientationDidChangeNotification
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(orientationDidChange:)
name:UIDeviceOrientationDidChangeNotification object:nil];
A useful technique for just this case is, to present a new modal view controller with a "fade" transition from your current view. You can do this in reaction to UIDeviceOrientationDidChangeNotification as mentioned previously by Aaron.
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];

Inaccurate device orientation returned by UIDeviceOrientationDidChangeNotification

I'm listening to the UIDeviceOrientationDidChangeNotification in order to adjust my UI based on the device's orientation.
The problem is that the device orientation I'm getting from the notification seems inaccurate. If I start with the phone in portrait orientation and vertical (as if taking a picture with it) the orientation I get from the notification is correct. As the tilt of the phone approaches horizontal (as in laying flat on a table top) the orientation switches to landscape. This happens much before the phone is actually flat on the table. And this is without rotating the phone towards landscape at all. Is as if it had a preference for landscape.
When using other apps, like mail, I don't see this same behavior. It seems that mail only switches orientation once it's really sure you've gone to the new orientation.
Any help greatly appreciated.
Thanks,
I found my problem.
In viewWillAppear I have:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver: self selector: #selector(didChangeOrientation:) name: UIDeviceOrientationDidChangeNotification object:
[UIDevice currentDevice]];
And here is the notification handler:
- (void) didChangeOrientation: (id)object {
UIInterfaceOrientation interfaceOrientation = [[object object] orientation];
//DLog(#"val is %i", interfaceOrientation);
if (interfaceOrientation == UIDeviceOrientationLandscapeLeft || interfaceOrientation == UIDeviceOrientationLandscapeRight || interfaceOrientation == UIDeviceOrientationPortrait) {
[self orientInterface:interfaceOrientation];
}
By checking that the orientation is one of the two landscapes or the two portraits I'm ignoring the UIDeviceOrientationFaceUp and UIDeviceOrientationFaceDown orientations. That way setting the phone in one of this two orientations won't have an effect on my interface's orientation.
My problem was that I was no considering the faceUp and faceDown and was handling them both in an else statement which was assuming landscape.
If your only interest is your interface orientation (ie landscape or portrait orientation of the device), you should NOT use UIDevice:orientation (or the UIDeviceOrientation* constants if you will), but rather use the UIApplication:statusBarOrientation, which uses the UIInterfaceOrientation* constants.
I use the following code to check for landscape modus:
static inline bool isOrientationIsLandscape() {
return UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]);
}
And for portrait modus:
static inline bool isOrientationIsPortrait() {
return UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation]);
}
This cost me a whole morning to figure out, because there is no UIDeviceOrientationFace[Up|Down] on the simulator, only on the real device. So my app worked on the simulator all the time, but on the actual device I had some undefined behavoir during testing every now and then.
Now it works on the actual device like it does on the simulator.
HTH
The notifications are just one way to get at it, you can also read out the accelerometer yourself and implement it in exactly the way you see fit (with a delay and a certain time of non-rotation for example).
Don't know if it's a power drain to get those readouts, but if so, use the notification to know when things are moving, and then fire up the accelometer-reading.