My game is implemented in a single SKScene object. A button (SKSpriteNode) lets the user switch from landscape to portrait mode. Well, it should. But I can't make this work. There are many discussions on this but they are all rather complicated and give suggestions that are completely different.
So.... What is the easiest way to make a button in an SKScene that changes the orientation to portrait or landscape?
Any suggestions are appreciated.
Here is a short, concise, complete answer to the question I posted.
In xcode, select File->New->Project->IOS->Application->Game to generate a default app framework for a game for IPad using SpriteKit with ObjectiveC. This is the classic HelloWorldApp where spinning airplanes appear whenever you touch the screen.
In Targets->DEploymentInfo->DeviceOrientation, checkmark Portrait and LandscapeLeft
Modify shouldAutorotate for the view controller like so...
- (BOOL)shouldAutorotate
{
int currentOrientation = (int)[[UIDevice currentDevice] orientation];
if (scene.orientation != currentOrientation) {
// Rotate the device back to orginial orientation
[[UIDevice currentDevice] setValue:
[NSNumber numberWithInteger: scene.orientation]
forKey:#"orientation"];
return NO;
}
return YES;
}
change the body of touchesBegan in your gameScene class like so...
-(void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
/* Called when a touch begins */
NSLog(#"%d", self.orientation);
if (!self.orientation || self.orientation == UIInterfaceOrientationPortrait) {
self.orientation = UIInterfaceOrientationLandscapeLeft;
} else {
self.orientation = UIInterfaceOrientationPortrait;
}
[[UIDevice currentDevice] setValue:
[NSNumber numberWithInteger: self.orientation]
forKey:#"orientation"];
the app will then hange orientation on each tap.
Related
I am creating a custom keyboard and I don't want to support for landscape mode. So, if a user rotates device to landscape mode then the keyboard must still be in portrait mode. I have tried the following methods:
-(BOOL)shouldAutorotate {
return NO;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
and
-(void)viewDidLoad{
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationPotrait];
[[UIDevice currentDevice] setValue:value forKey:#"orientation"];
}
But none of the methods works. The only method fires while rotating the device is this:
-(void)viewWillTransitionToSize:(CGSize)size
withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
Here I'm getting the current view size after rotation. But how do I stop the rotation? Any help will be appreciated.
If you are creating a custom keyboard for your app itself, then It should be controllable.
Ideally the orientation is inherited from the last heirarchial or the current visible view Controller of the app.
But if you are creating a third party keyboard application then Custom keyboard is kind of app overlayed on other app where as the orientation is still inherited from the app which is in the keywindow currently. I think custom keyboard cannot be limited to a particular orientation so that user feels convienient in using all the apps with that custom keyboard.
Could you please try the same on viewDidAppear
-(void)viewDidAppear:(BOOL)animated{
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationPotrait];
[[UIDevice currentDevice] setValue:value forKey:#"orientation"];
}
Without going into the 'why' of it all, I have UITextField that is part of a view hierarchy that is forcibly 'upside down' on screen via an affine transform.
CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(180))
This works fine for all of the subviews -- including the UITextField -- until the user wants to use the copy/paste features of UIMenuController on the text field content. When the UIMenuController is shown, it is 'right side up' rather than 'upside down' like the UITextField.
Is there anyway to get a hold of the UIMenuController's view to apply the same transform when it is shown?
Currently, I am listening for the UIMenuControllerWillShowMenuNotification notification and then getting the UIMenuController. But I can't seem to find a way to apply the transform to it. Any ideas?
- (void)textFieldDidBeginEditing:(UITextField *)textField {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(menuControllerWillShow:) name:UIMenuControllerWillShowMenuNotification object:nil];
}
- (void)menuControllerWillShow:(NSNotification*)aNotification {
UIMenuController* menuController = [UIMenuController sharedMenuController];
CGAffineTransform xform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(180));
CGRect oldRect = menuController.menuFrame;
CGRect newRect = CGRectApplyAffineTransform(oldRect, xform);
// eh... now what?
}
I don't think you can modify the UIMenuController so it's upside down.
But if it's pretty much your entire app that's altered, you could either check the device orientation or the app orientation (by checking where the status bar is) and force it to be the opposite.
To get the device orientation you could do something like this:
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation]
Note from the docs:
The value of this property always returns 0 unless orientation notifications have been enabled by calling beginGeneratingDeviceOrientationNotifications.
Or get the app orientation with this:
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if(orientation == 0) //Default orientation
{
//UI is in Default (Portrait) -- this is really a just a failsafe.
}
else if(orientation == UIInterfaceOrientationPortrait)
{
//Do something if the orientation is in Portrait
}
else if(orientation == UIInterfaceOrientationLandscapeLeft)
{
// Do something if Left
}
else if(orientation == UIInterfaceOrientationLandscapeRight)
{
//Do something if right
}
and then set it with something like this:
Objective-C:
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
[[UIDevice currentDevice] setValue:value forKey:#"orientation"];
Swift:
let value = UIInterfaceOrientation.LandscapeLeft.rawValue
UIDevice.currentDevice().setValue(value, forKey: "orientation")
UIDeviceOrientationDidChangeNotification is calling multiple times when the device changes orientation. I am unsure why this happens or how to fix it.
What I am trying to do is to keep the contentoffset of the scrollview the same, so when the user rotates the screen the app keeps the page they were on.
The odd thing is when I rotate the screen the first time the code executes like I would want. But every time after that the code executes multiple times and eventually the contentoffset is set o 0.
Here's what I have.
- (void)loadView {
//some code that sizes itself depending on the current orientation
//WILL BE CALLED AFTER EVERY ORIENTATION CHANGE
}
- (void)viewDidLoad {
//begin generating messages
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter]
addObserver:self selector:#selector(orientationChanged:)
name:UIDeviceOrientationDidChangeNotification
object:[UIDevice currentDevice]];
//if is portrait and was landscape
if (orientation==1 && temp==2) {
int cal = offsetHolder.x/screenframe.size.height;
offsetHolder.x = cal * screenframe.size.width;
ScrollView.contentOffset = offsetHolder;
}
//if is landscape and was portrait
if (orientation==2 && temp==1) {
int cal = offsetHolder.x/screenframe.size.width;
offsetHolder.x = cal * screenframe.size.height;
ScrollView.contentOffset = offsetHolder;
}
}
On orientation change I change the value of 'int orientation' then call loadview to change the sizing of the view. Then I call viewdidload to get the proper contentoffset
- (void) orientationChanged:(NSNotification *)note {
CGRect screenframe = [[UIScreen mainScreen] bounds];
//holding the current offset
offsetHolder = ScrollView.contentOffset;
if ([[UIDevice currentDevice] orientation] == 1 || [[UIDevice currentDevice] orientation] == 0 || [[UIDevice currentDevice] orientation] == UIDeviceOrientationPortraitUpsideDown) {
temp=orientation;
orientation = 1;
[self loadView];
[self viewDidLoad];
}
else if ([[UIDevice currentDevice] orientation] == UIDeviceOrientationFaceDown || [[UIDevice currentDevice] orientation] == UIDeviceOrientationFaceUp){
temp=orientation;
}
else{
temp=orientation;
orientation = 2;
[self loadView];
[self viewDidLoad];
}
}
EDIT:
I have found the problem. What I am doing is creating another instance of self.view instead of overwriting this one. Is there an easy way to destroy this view and re-initialize it?
EDIT2:
Have found a fix. I stopped calling loadview and viewdidload as per jsds' instructions. And instead moved all code in my loadview to another function that I called from loadview. All this code does is instantiate the UI (initview) objects and places them in the correct places depending upon orientation.
Then I create another function that removes all subviews from the view. Then on orientation change I call this function and my initview to destroy all subviews and then recreate them on orientation change.
UIDeviceOrientation basically has 6 different states, namely two portrait, two landscape, and face up and face down. So lets say when you pick up your device from flat position to vertical position, the notification will be triggered.
You can filter the faceup, facedown, and unknown states by using the macro UIDeviceOrientationIsValidInterfaceOrientation
UIDeviceOrientation currentOrientation = [[UIDevice currentDevice] orientation];
// Ignore changes in device orientation if unknown, face up, or face down.
if (!UIDeviceOrientationIsValidInterfaceOrientation(currentOrientation)) {
return;
}
If you still find the notification getting triggered multiple times, I am afraid you may need to use your custom logic with flags to check the previous and current value.
In my case, since I use reactive cocoa framework, the following code works for me :
if (IS_IPAD) {
#weakify(self);
[[[[[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIDeviceOrientationDidChangeNotification object:nil]
takeUntil:[self rac_willDeallocSignal]]
map:^id (NSNotification *notification) {
return #([[UIDevice currentDevice] orientation]);
}]
filter:^BOOL(NSNumber *deviceOrientationNumber) {
UIDeviceOrientation currentOrientation = [deviceOrientationNumber integerValue];
//We ignore the UIDeviceOrientationUnknown, UIDeviceOrientationFaceUp and UIDeviceOrientationFaceDown
return UIDeviceOrientationIsValidInterfaceOrientation(currentOrientation);
}]
distinctUntilChanged]
subscribeNext:^(id x) {
#strongify(self);
//do something here...
}];
}
Here the distinctUntilChanged method makes sure the code gets triggered only when the orientation changes to a new valid value.
You should never call loadView or viewDidLoad yourself. That's up to the framework to manage.
If you are positioning or resizing views based on the view bounds in viewDidLoad, don't. Move that to viewWillLayoutSubviews. That will be called automatically when the device orientation changes.
Alternatively, use autolayout constraints and then you won't have to do anything at all.
This question already has answers here:
Force landscape mode in one ViewController using Swift
(20 answers)
Closed 1 year ago.
In iOS 5 we could change the device orientation programmatically like so:
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];
But in iOS 6 setOrientation is deprecated, how may i change the device orientation programmatically in iOS 6?
Here are my "five cents", tested on iOS7 with ARC
[[UIDevice currentDevice] setValue:
[NSNumber numberWithInteger: UIInterfaceOrientationPortrait]
forKey:#"orientation"];
This doesnt generate "leak" warning as performSelector will.
UIAlertView - with this code, when you open UIAlertView during view(will/Did)appear you will notice that all but this view is in portrait (apple, really?) I wasn't able to force the view to reorient but found that if you put slight delay before opening the UIAlertView then view has time to change orientation.
Note I'm releasing my app week commencing 12/09/2014 and I will update post if it will pass or fail.
I found out that the easiest way to force the device to change orientation is to present a new view controller (using presentViewController:animated:completion:) where the new view controller specified a particular preferred orientation (by implementing the method -(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation).
When a new view controller is presented, as expected, the orientation will change to the one preferred by the new view controller. So, simplest implementation (best practice?) will be to embed all functionality you needed in a specific orientation into a separate view controller, and present it as needed. The system will take care of changing the orientation for you.
Obviously this might not suit all use cases, but, fortunately the same trick is applicable to force the device to change orientation for existing view controller.
The trick is to present a new view controller with the specific preferred orientation that you needed, and then hide it immediately. This will cause the orientation to change temporary when the new view controller is presented. The best part is, when the new view controller is dismissed, the original (presenting) view controller's preferredInterfaceOrientationForPresentation is queried again, you can specify the final orientation you want here.
One important thing to look out here is to also temporary disable auto rotation in the original view controller (when coming back from the newly presented-then-dismissed view controller), so that when user rotate their phone towards the new orientation, it does not triggered further auto rotation.
The following code should illustrate my point, my example forces rotation to portrait, just change accordingly if you want other orientation.
Assuming you have the original view controller named Original, and a temporary view controller named ForcePortrait
#interface Original : UIViewController
{
BOOL orientationToPortrait; //should set to NO by default
}
#end
#implementation Original
- (UIInterfaceOrientation) preferredInterfaceOrientationForPresentation
{
if(orientationToPortrait)
{
//when we manually changed, show in Portrait
return UIInterfaceOrientationPortrait;
}
else
{
//before manual orientation change, we allow any orientation
return self.interfaceOrientation;
}
}
-(BOOL) shouldAutorotate
{
//we should 'lock' the rotation once we manually change it
return !orientationToPortrait;
}
-(void) changeOrientationToPortrait
{
//Sample method to change the orientation
//when called, will show (and hide) the temporary view
//Original.preferredInterfaceOrientationForPresentation will be called again after this method
//flag this to ensure that we tell system we prefer Portrait, whenever it asked again
orientationToPortrait = YES;
//presenting the following VC will cause the orientation to temporary change
//when the new VC is dismissed, system will ask what is our (Original) orientation preference again
ForcePortrait* forcePortrait = [[ForcePortrait alloc] init];
[self presentViewController:forcePortrait animated:NO completion:^{
[forcePortrait dismissViewControllerAnimated:NO completion:nil];
}];
}
#end
#interface ForcePortrait : UIViewController
#end
#implementation ForcePortrait
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
#end
This does not answer how to change the device Orientation, but an additional information that might help you.
iOS 6 UI Interface Orientation - shouldAutorotateToInterfaceOrientation: Not Working
The method shouldAutorotateToInterfaceOrientation: is NOT supported in iOS 6. Its deprecated. Just in case if you are a newbie, who just stared working in cocoa, and wondering why is your view controller messed up in iOS 6 and perfect in iOS 5, just know that shouldAutorotateToInterfaceOrientation: is not supported anymore. Even though it may work well with Xcode 4 to 4.3 it will NOT work on Xcode 4.5.
Apple provides a new method to get this thing done, in a much cleaner fashion. You use supportedInterfaceOrientations instead. It returns all of the interface orientations that the view controller supports, a mask of interface orientation values.
UIInterfaceOrientationMask Enum:
These constants are mask bits for specifying a view controller’s supported interface orientations.
typedef enum {
UIInterfaceOrientationMaskPortrait = (1 << UIInterfaceOrientationPortrait),
UIInterfaceOrientationMaskLandscapeLeft = (1 << UIInterfaceOrientationLandscapeLeft),
UIInterfaceOrientationMaskLandscapeRight = (1 << UIInterfaceOrientationLandscapeRight),
UIInterfaceOrientationMaskPortraitUpsideDown = (1 << UIInterfaceOrientationPortraitUpsideDown),
UIInterfaceOrientationMaskLandscape =
(UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight),
UIInterfaceOrientationMaskAll =
(UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft |
UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskPortraitUpsideDown),
UIInterfaceOrientationMaskAllButUpsideDown =
(UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft |
UIInterfaceOrientationMaskLandscapeRight),
} UIInterfaceOrientationMask;
Using shouldAutorotateToInterfaceOrientation: method:
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
return UIInterfaceOrientationIsLandscapeRight(toInterfaceOrientation);
}
Using supportedInterfaceOrientations method:
-(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskLandscapeRight;
}
These are the added methods to UIViewController regarding Orientation in iOS6
UIViewController preferredInterfaceOrientationForPresentation
UIViewController shouldAutorotate
UIViewController supportedInterfaceOrientations
Added methods to UIApplication regarding Orientation in iOS6
UIApplication supportedInterfaceOrientationsForWindow:
UIInterfaceOrientationMask
Try this:
#import <objc/message.h>
if(UIDeviceOrientationIsLandscape(self.interfaceOrientation)){
if ([[UIDevice currentDevice] respondsToSelector:#selector(setOrientation:)])
{
objc_msgSend([UIDevice currentDevice], #selector(setOrientation:), UIInterfaceOrientationPortrait );
}
}
You should place
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
in your AppDelegate didFinishLaunchingWithOptions Method.
Then, anywhere in your application you can get the current orientation with:
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
And test orientation with:
UIInterfaceOrientationIsPortrait(orientation)
UIInterfaceOrientationIsLandscape(orientation)
as, like
if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation))
{
// code for landscape orientation
// OR
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];
// OR
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeLeft];
}
else if (UIDeviceOrientationIsPortrait([UIDevice currentDevice].orientation))
{
// code for Portrait orientation
// OR
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortraitUpsideDown];
// OR
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait];
}
This code is for iOS 8 or later
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
[[UIDevice currentDevice] setValue:value forKey:#"orientation"];
Try this...It worked out for me...
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
UIView *view = [window.subviews objectAtIndex:0];
[view removeFromSuperview]; [window addSubview:view];
#implementation UINavigationController (autorotate)
-(NSUInteger)supportedInterfaceOrientations
{
//make the check for iphone/ipad here
if(IPHONE)
{
return UIInterfaceOrientationMaskPortrait;
}
else
{
return UIInterfaceOrientationMaskLandscape;
}
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
- (BOOL)shouldAutorotate
{
return NO;
}
A little modification to Bissy's answer, if you want to avoid using Runtime Library:
if (UIDeviceOrientationIsLandscape([[UIDevice currentDevice] orientation]))
{
if ([[UIDevice currentDevice] respondsToSelector:#selector(setOrientation:)])
{
int orientationPortrait = UIInterfaceOrientationPortrait;
NSMethodSignature *sig = [[UIDevice currentDevice] methodSignatureForSelector:#selector(setOrientation:)];
NSInvocation* invo = [NSInvocation invocationWithMethodSignature:sig];
[invo setTarget:[UIDevice currentDevice]];
[invo setSelector:#selector(setOrientation:)];
[invo setArgument:&orientationPortrait atIndex:2];
[invo invoke];
}
}
This works for iOS7, force autorotate to portrait.
//In your viewController.m
#import <objc/message.h>
// for autorotate viewController to portraid
- (void)viewWillAppear:(BOOL)animated {
UIInterfaceOrientation orientationStatusBar =[[UIApplication sharedApplication] statusBarOrientation];
switch (orientationStatusBar) {
case UIInterfaceOrientationPortrait:break;
case UIInterfaceOrientationLandscapeLeft:
objc_msgSend([UIDevice currentDevice], #selector(setOrientation:), UIInterfaceOrientationPortrait);
break;
case UIInterfaceOrientationLandscapeRight:
objc_msgSend([UIDevice currentDevice], #selector(setOrientation:), UIInterfaceOrientationPortrait);
break;
default:
break;
}
}
// this permit autorotate
- (BOOL) shouldAutorotate
{
// this lines permit rotate if viewController is not portrait
UIInterfaceOrientation orientationStatusBar =[[UIApplication sharedApplication] statusBarOrientation];
if (orientationStatusBar != UIInterfaceOrientationPortrait) {
return YES;
}
//this line not permit rotate is the viewController is portrait
return NO;
}
NOTE: I implemented this option in my app, but probably would get rejected by Apple (comment for Austin for edited 6 of Sergey K. in oct 2012).
Apple made changing the device orientation programmatically in ios6 quite difficult (on purpose mind you).
As far as I know the only way to accomplish what you're asking is to simulate the change of device orientation.
Using setTransform to rotate the UIView and re-applying its own frame gives the desired results.
[YourView setTransform:CGAffineTransformMakeRotation(1.57)];
[YourView setFrame:CGRectMake(0, 0, YourView.frame.size.width, YourView.frame.size.height)];
And when the device physical orientation changes we can undo the transformation.
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
[YourView setTransform:CGAffineTransformMakeRotation(0)];
[YourView setFrame:CGRectMake(0, 0, YourView.frame.size.width, YourView.frame.size.height)];
}
if (self.interfaceOrientation != UIInterfaceOrientationLandscapeRight) {
// http://stackoverflow.com/questions/181780/is-there-a-documented-way-to-set-the-iphone-orientation
// http://openradar.appspot.com/radar?id=697
// [[UIDevice currentDevice] setOrientation: UIInterfaceOrientationLandscapeRight]; // Using the following code to get around apple's static analysis...
[[UIDevice currentDevice] performSelector:NSSelectorFromString(#"setOrientation:") withObject:(id)UIInterfaceOrientationLandscapeRight];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return NO;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return interfaceOrientation == UIInterfaceOrientationPortrait
|| interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown ;
}
This works for me on Xcode 6 & 5.
- (BOOL)shouldAutorotate {return YES;}
- (NSUInteger)supportedInterfaceOrientations {return (UIInterfaceOrientationMaskPortrait);}
Its interesting how others didn't run to problems after not setting it like this :
+ (void)setOrientation:(UIDeviceOrientation)orientation {
[UIDevice.currentDevice setValue:#(orientation) forKey:#"orientation"];
[UIViewController attemptRotationToDeviceOrientation];
[UIDevice.currentDevice setValue:#(UIDeviceOrientationUnknown) forKey:#"orientation"];
}
My requirement was to be able to force orientation and then again rotate to device natural orientation... there is UIDeviceOrientationDidChangeNotification that can get you de information to witch orientation to rotate device back but actually it will partly not work if you don't set to unknown immediately after you changed orientation in UIDevice, also there are more details to make it cool but will leave it, as it is out of context of this simple question.
In a given event handler (not the "shouldAutorotateToInterfaceOrientation" method) how do I detect the current iPad orientation? I have a text field I have to animate up (when keyboard appears) in the Landscape view, but not in the portrait view and want to know which orientation I'm in to see if the animation is necessary.
Orientation information isn't very consistent, and there are several approaches. If in a view controller, you can use the interfaceOrientation property. From other places you can call:
[[UIDevice currentDevice] orientation]
Alternatively, you can request to receive orientation change notifications:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
Some people also like to check the status bar orientation:
[UIApplication sharedApplication].statusBarOrientation
I think
[[UIDevice currentDevice] orientation];
is not really reliable. Sometimes it works, sometimes not... In my apps, I use
[[UIApplication sharedApplication]statusBarOrientation];
and it works great!
One of:
Check the interfaceOrientation property of the active view controller.
[UIApplication sharedApplication].statusBarOrientation.
[UIDevice currentDevice].orientation. (You may need to call -beginGeneratingDeviceOrientationNotifications.)
I found a trick to solve the FaceUp orientation issue!!!
Delay the orientation check till AFTER the app has started running, then set variables, view sizes, etc.!!!
//CODE
- (void)viewDidLoad {
[super viewDidLoad];
//DELAY
[NSTimer scheduledTimerWithTimeInterval:0.5
target:self
selector:#selector(delayedCheck)
userInfo:nil
repeats:NO];
}
-(void)delayedCheck{
//DETERMINE ORIENTATION
if( [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortrait ){
FACING = #"PU";
}
if( [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortraitUpsideDown ){
FACING = #"PD";
}
if( [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft ){
FACING = #"LL";
}
if( [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight ){
FACING = #"LR";
}
//DETERMINE ORIENTATION
//START
[self setStuff];
//START
}
-(void)setStuff{
if( FACING == #"PU" ){
//logic for Portrait
}
else
if( FACING == #"PD" ){
//logic for PortraitUpsideDown
}
else{
if( FACING == #"LL"){
//logic for LandscapeLeft
}
else
if( FACING == #"LR" ){
//logic for LandscapeRight
}
}
//CODE
You can addSubviews, position elements, etc. in the 'setStuff' function ... anything that would initially depend on the orientation!!!
:D
-Chris Allinson
You can achieve this by two ways:
1- By using the following method:
**Put the following line in the -(void)viewDidLoad Method:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(deviceRotated:) name:UIDeviceOrientationDidChangeNotification object:nil];
then put this method inside your class
-(void)deviceRotated:(NSNotification*)notification
{
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
if(orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight)
{
//Do your textField animation here
}
}
The above method will check the orientation when the device will be rotated
2- The second way is by inserting the following notification inside -(void)viewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(checkRotation:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
then put the following method inside your class
-(void)checkRotation:(NSNotification*)notification
{
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if(orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight)
{
//Do your textField animation here
}
}
The above method will check the orientation of the status bar of the ipad or iPhone and according to it you make do your animation in the required orientation.
For determining landscape vs portrait, there is a built-in function:
UIInterfaceOrientation orientation = [[UIDevice currentDevice] orientation];
BOOL inLandscape = UIDeviceOrientationIsLandscape(orientation);
[UIApplication sharedApplication].statusBarOrientation returns portrait when it's landscape, and landscape when it's portrait at launch, in iPad
I don't know why, but every time my app starts, the first 4 are right, but subsequently I get the opposite orientation. I use a static variable to count this, then have a BOOL to flip how I manually send this to subviews.
So while I'm not adding a new stand-alone answer, I'm saying use the above and keep this in mind. Note: I'm receiving the status bar orientation, as it's the only thing that gets called when the app starts and is "right enough" to help me move stuff.
The main problem with using this is the views being lazily loaded. Be sure to call the view property of your contained and subviews "Before" you set their positions in response to their orientation. Thank Apple for not crashing when we set variables that don't exist, forcing us to remember they break OO and force us to do it, too... gah, such an elegant system yet so broken! Seriously, I love Native, but it's just not good, encourages poor OO design. Not our fault, just reminding that your resize function might be working, but Apple's Way requires you load the view by use, not by creating and initializing it
In your view controller, get the read-only value of self.interfaceOrientation (the current orientation of the interface).
I've tried many of the above methods, but nothing seemed to work 100% for me.
My solution was to make an iVar called orientation of type UIInterfaceOrientation in the Root View Controller.
- (void)viewDidLoad {
[super viewDidLoad];
orientation = self.interfaceOrientation; // this is accurate in iOS 6 at this point but not iOS 5; iOS 5 always returns portrait on app launch through viewDidLoad and viewWillAppear no matter which technique you use.
}
- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
return YES;
}
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
orientation = toInterfaceOrientation;
}
Then, any place where you need to check the orientation you can do something like this:
if(UIInterfaceOrientationIsPortrait(orientation)){
// portrait
}else{
// landscape
}
There may still be a better way, but this seems to work 98% of the time (iOS5 notwithstanding) and isn't too hard. Note that iOS5 always launches iPad in portrait view, then sends a device the willRotateTo- and didRotateFromInterfaceOrientation: messages, so the value will still be inaccurate briefly.
[UIDevice currentDevice].orientation works great.
BUT!!!
... the trick is to add it to - (void)viewWillAppear:(BOOL)animated
exp:
(void)viewWillAppear:(BOOL)animated{
...
BOOL isLandscape = UIInterfaceOrientationIsLandscape(self.interfaceOrientation);
...
}
If you call it at - (void)viewDidLoad, it does not work reliable, especially if you use multiple threads (main UI thread, background thread to access massive external data, ...).
Comments:
1) Even if your app sets default orientation portrait, user can lock it at landscape. Thus setting the default is not really a solution to work around it.
2) There are other tasks like hiding the navigation bar, to be placed at viewWillAppear to make it work and at the same time prevent flickering. Same applies to other views like UITableView willDisplayCell -> use it to set cell.selected and cell.accessoryType.