Views moved out of place when rotating - uiview

I created a UIViewController (based on How to switch views when rotating) to switch between 2 views when the device rotates. Each view is "specialized" for a particular orientation.
It uses the UIDeviceOrientationDidChangeNotification notification to switch views:
-(void) deviceDidRotate: (NSNotification *) aNotification{
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
NSLog(#"Device rotated to %d!", orientation);
if ((orientation == UIDeviceOrientationPortrait) ||
(orientation == UIDeviceOrientationPortraitUpsideDown)) {
[self displayView:self.portraitViewController.view];
}else if ((orientation == UIDeviceOrientationLandscapeLeft) ||
(orientation == UIDeviceOrientationLandscapeRight)) {
[self displayView:self.landscapeViewController.view];
}
}
and sort of works. The problems shows up when I rotate to Landscape and then back to Portrait. When going back to portrait the subviews aren't displayed in the right place, specially the UIPickerView:
First Time Portrait:
Rotate to Landscape:
Back to Portrait:
If I repeat the rotation process, things just get worse. What am I doing wrong?
The source code is here: http://dl.dropbox.com/u/3978473/forums/Rotator.zip
Thanks in advance!

To solve your offset problems, rewrite the displayView: method as below.
-(void) displayView: (UIView *)aView{
self.view = aView;
}
Rotations however are strange. you should review that part of code.
Use the UIViewController rotation methods
(void)willRotateToInterfaceOrientation:duration:
(void)didRotateFromInterfaceOrientation:
instead of -(void)deviceDidRotate:
Much simpler, you will avoid that strange bouncing, and you don't need notifications any more.
Do some reading on the apple documentation on the methods i specified above.
Hope this helps.

OK, I found the error. It's pretty simple and stupid: I mixed frame and bounds.
In the displayView: code I was setting the frame of the child view to the frame of the parent view, when it should be the bounds of the parent.

Related

Device Orientation results in flipped node location

My code is very simple. I want to change the positioning of an SKSpriteNode to always remain in the bottom right corner of the device screen. I call my UIDeviceOrientationDidChangeNotification method "rotated" on device rotation and it should simply move the node, but for some reason it always flips the desired location so the landscape position is where the portrait should be and vice-versa.
My code is as follows:
UI
- (void)rotated:(NSNotification *)notification {
DeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
if (UIDeviceOrientationIsLandscape(deviceOrientation) && !_isShowingLandscapeView)
[self.node setPosition:bottom_right];
_isShowingLandscapeView = YES;
}
else if (UIDeviceOrientationIsPortrait(deviceOrientation) && _isShowingLandscapeView)
{
[self.node setPosition:bottom_right];
_isShowingLandscapeView = NO;
}
}
Ok so what I'm doing is simple. Just use UIButtons over your SKScene. Go back to the UIViewController where you call your skscene from and add buttons. You'll have to use NSNotification center to pass information to the buttons, labels, etc.
http://www.raywenderlich.com/forums/viewtopic.php?f=2&t=8843

UIViewController interface orientation is wrong

In the UIViewController rotation method(s) I have a problem when performing the device rotation
inside of the method
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
I am getting incorrect values
According to the documentation:
Sent to the view controller just before the user interface begins
rotating. Subclasses may override this method to perform additional
actions immediately prior to the rotation. For example, you might use
this method to disable view interactions, stop media playback, or
temporarily turn off expensive drawing or live updates. You might also
use it to swap the current view for one that reflects the new
interface orientation. When this method is called, the
interfaceOrientation property still contains the view’s original
orientation. Your implementation of this method must call super at
some point during its execution. This method is called regardless of
whether your code performs one-step or two-step rotations.
I am holding the device strait up (right after launching the app the device is physically in portrait mode) - all the views are correctly aligned for portrait mode
But in the method I am getting wrong values:
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
// getting the wrong interface orientation here!!!!
// just checking the current orientation for debug
UIInterfaceOrientation currentOrientation = self.interfaceOrientation;
// the first time the device is rotated getting this value for current orientation:
// currentOrientation == UIInterfaceOrientationLandscapeRight
}
even worst than this strange case of wrong orientation is in this same method for 'will rotate to interface orientation' the current interface orientation and the destination interface orientation are identical i.e:
self.interfaceOrientation === toInterfaceOrientation
So whats the point of this method being called by the framework???
This results in all my UIView placement code not being calculating correctly on initial rotation of the device.
Why is this flag not set correctly?!?!
P.S
After rotating the device for the second time - the flags are set correctly and the views "align" themselves properly.
u will get correct value, suppose u are holding the device in port rite , then u turn it t landscape mode, then this method is called
//called first
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
//check which orientation hear
if(toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft || toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
NSLog(#"turning t landscape");
}
else
{
NSLog(#"turning t portrite");
}
}
method called hear toInterfaceOrientation contains (for our example) UIInterfaceOrientationLandscapeRightorUIInterfaceOrientationLandscapeLeft`, this indicates that device will going to turn to landscape left or rite
after this, below methods called in order
- (void)viewWillLayoutSubviews
- (void)willAnimateRotationToInterfaceOrientation:duration:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
get called, hear in last method fromInterfaceOrientation contains (for our example) old value or previous orientation flag, that is UIInterfaceOrientationPortraitUpsideDown or UIInterfaceOrientationPortrait
u want t know the current orientation then u can use
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
if(UIInterfaceOrientationIsLandscape(orientation))
{
NSLog(#"landscape");
}
else
{
NSLog(#"portrite");
}
for more information about this u can see this docs

iPad shows at portrait but thinks it's landscape

My Storybuilder is designed with a portrait layout. When I start the app with my iPad already turned to horizontal, it's able to correctly detect it's in a horizontal position. But when I start the app with my iPad in a portrait position, it thinks it's in horizontal. However, every time I rotate it, the code is able to detect the correct orientation properly.
- (void) viewDidLoad
{
[self updateForOrientation];
}
- (void)updateForOrientation
{
if (UIInterfaceOrientationIsPortrait([[UIDevice currentDevice] orientation])) // became portrait
{
NSLog(#"is portrait");
//code for changing layout to portrait position
}
else //became horiztontal
{
NSLog(#"is horizontal");
//code for changing layout to horizontal position
}
}
Output: is horizontal (this is the output whether it starts up as portrait or landscape)
The problem is that you're sending the devices orientation in terms of the UIDeviceOrientation enum to a function that's expecting a UIInterfaceOrientation value.
If you command click on UIInterfaceOrientationIsPortrait(), you can see that it is defined as follows.
#define UIInterfaceOrientationIsPortrait(orientation) ((orientation) == UIInterfaceOrientationPortrait || (orientation) == UIInterfaceOrientationPortraitUpsideDown)
And if you look at the enum declarations for the two orientation types (documentation links below), you can see that there is a misalignment in value due to the device orientation containing a value for "none". Anyway, changing your code to use UIInterfaceOrientation should sort this out. Example:
- (void)updateForOrientation
{
UIInterfaceOrientation currentOrientation = self.interfaceOrientation;
if (UIInterfaceOrientationIsPortrait(currentOrientation)) {
NSLog(#"is portrait");
}else{
NSLog(#"is horizontal");
}
}
https://developer.apple.com/library/ios/documentation/uikit/reference/UIApplication_Class/Reference/Reference.html#//apple_ref/doc/c_ref/UIInterfaceOrientation
https://developer.apple.com/library/ios/documentation/uikit/reference/UIDevice_Class/Reference/UIDevice.html#//apple_ref/doc/c_ref/UIDeviceOrientation

iPad stop screen from Rotating Xcode 4

I am building an iPad app in Xcode 4. The app is suposed to always show in Landscape view. to achieve this I have tried the following:
In the Target summary screen I selecte only Landscape Left as a Supported Device Orentation.
In the Target Info screen / Info.plist set the Supported interface orientations(iPad) to Landscape (left home button)
This leads the app the to start in landscape mode, but if I rotate the device it still changes its orientation. Also, when I have a UIViewController presented with presentationStyle UIPresentationFormSheet it rotates to portrait the moment it shows.
In some other threads / forums it was adviced to create a category for UIViewController and rewrite
-(UIDeviceOrientation)interfaceOrientation;
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation;
To always rotate to the Device Orientation (LandscapeLeft) or specifically LandscapeLeft, also to no AutoRotate unless you rotate to LandscapeLeft.
When I set these functions like this (Or for example allow no rotation at all) the app always appears in portrait mode, and wont rotate, not even to LandscapeLeft. The only way to have the app start in Landscape mode is when I allow for rotation no matter what the interfaceOrientaton is.
Does anybody know how I can fix this?
The category I implemented:
#implementation UIViewController(Extends)
-(UIDeviceOrientation)interfaceOrientation
{
return [[UIDevice currentDevice] orientation];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
if(interfaceOrientation == UIInterfaceOrientationLandscapeLeft)
return YES;
else
return NO;
}
#end
The only place that I can find a Portrait Orientation to be defined is the original window on the MainWindow.xib, but this cannot be altered, and every thread/forum says that that particular setting is/should not be the issue.
As far as I can tell the steps you took should prevent rotation of the interface.
You can always try to override the calls that do the orientation in every viewcontroller of your app. That should at least give you a clue where the rotation is happening. After which a breakpoint can possibly tell you more.
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration {
NSLog( #"will rotate to orientation %d in %#", interfaceOrientation, NSStringFromClass([self class])
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
NSLog( #"did rotate from orientation %d to %d in %#", fromInterfaceOrientation, [self interfaceOrientation], NSStringFromClass([self class])
}

Is there a way to force the interface orientation to change in iPhone?

I know how to allow/disallow the orientation to rotate using
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
However, I have the problem now where the phone might be in portrait (or upsidedown) and at some point I want to rotate the screen as if the user rotated to landscape. At this point, I don't want autorotate to work anymore. I want to force the interface orientation to stay in landscape. Is there a way to do this? I can probably figure out a hack for turning off the autorotate, but forcing the rotation in the first place I have no idea how to do.
Here's what I'm trying to do:
The app rotates to any and all orientations. Everything is normal.
An event occurs.
Now the autorotate only works for landscapeleft and landscaperight. Moreover, if the user is in portrait or portraitupsidedown, I programmatically rotate to landscaperight to lock the user into that orientation.
Just to make things trickier, I want to pop up a UIAlertView (I know how to do that) before the forced rotation, letting the user know what's going on, and I want to screen behind the alertView to rotate but not the alertView. Is this even possible?
Thanks.
The best solution for your situation is to notify the user to turn it to landscape orientation and pause the program until the user turns the orientation. And then when the user rotates the device you can handle the delegate methods and start displaying the screen in the landscape mode. This approach has been handled in many of the app store applications and looks like it is one of the best ways to get the app approved in app store. I hope it makes sense.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown || interfaceOrientation == UIInterfaceOrientationLandscapeRight || interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}
// orientation view swapping logic
- (void)didRotate:(NSNotification *)notification {
UIDeviceOrientation newOrientation = [[UIDevice currentDevice] orientation];
if (newOrientation != UIDeviceOrientationUnknown || newOrientation != UIDeviceOrientationFaceUp || newOrientation != UIDeviceOrientationFaceDown)
{
orientation = newOrientation;
}
// Write your orientation logic here
if ((orientation == UIDeviceOrientationLandscapeLeft || orientation == UIDeviceOrientationLandscapeRight))
{
// Clear the current view and insert the orientation specific view.
[self clearCurrentView];
[self.view insertSubview:yourLandscapeView atIndex:0];
} else if (orientation == UIDeviceOrientationPortrait || orientation == UIDeviceOrientationPortraitUpsideDown)
{
// Clear the current view and insert the orientation specific view.
[self clearCurrentView];
[self.view insertSubview:yourPortraitView atIndex:0];
}
}
and add that notification in the event
You cannot. At least not in a way that Apple will allow. The autorotation is designed to be the same for the whole application. You can make code that rotates the view manually, but as far as UIDevice is concerned you'll be in the same orientation.
According to Apple, if you do not want the default behavior provided by the device orientation rotation API:
You can take control over:
The orientations supported by your app
How a rotation between two orientations is animated on screen.
The way I read this is "You can control either of these things, but nothing else" or "You're allowed to control only these two things."
I do not see anything in the documentation that explicitly tells you how to "force" the orientation to change. All of that is handled by the device so as it seem more natural and friendly to the person holding the device. Does that make sense?
See the docs here on rotation changes:
http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/RespondingtoDeviceOrientationChanges/RespondingtoDeviceOrientationChanges.html
Finally, I would say this is not possible, and further that it would not be approved by Apple. I up voted Praveen's answer because I think you may need to consider a different approach for what you're trying to do.
yes you ca do that. what you have to do is in -(void) viewwillappear method simply include the following code
if (self.interfaceOrientation == <current orientation>) {
[[UIDevice currentDevice] performSelector:NSSelectorFromString(#"setOrientation:") withObject:(id)<to which orientation you want to change.>];
}
it will solve your problem

Resources