iOS: Force apply current device orientation after callback - ios

I'm currently building an iOS app (supporting iOS >= 8) that has initial splash screen animation on start up. This animation blocks the entire screen during 2~3 seconds and then hides itself.
Goal is that the screen orientation should be fixed to portrait mode, and be released when the animation is over. This can be easily achieved by the following code:
- (void)onSplashAnimationEnded {
_isFinished = YES;
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
if (_isFinished) {
return UIInterfaceOrientationMaskAll;
}
return UIInterfaceOrientationMaskPortrait;
}
The problem is that when a user launched the app in landscape mode, and when the animation is finished, the device orientation (currently in landscape mode) does not apply to the app (locked in portrait mode, as intended).
It seems natural that the current orientation of device is automatically applied to the app right after the animation is over. I tried the followings to solve this and none of them works.
- (void)onSplashAnimationEnded {
_isFinished = YES;
// #1
[UIViewController attemptRotationToDeviceOrientation];
// #2
[[NSNotificationCenter defaultCenter] postNotificationName:UIDeviceOrientationDidChangeNotification object:[UIDevice currentDevice]];
// #3
[[NSNotificationCenter defaultCenter] postNotificationName:UIApplicationDidChangeStatusBarOrientationNotification object:[UIApplication sharedApplication]];
}
I really hope someone to share any workarounds for this issue.
Edit #1
I have read the other question that is linked to mine, and want to add some detail about it.
It is possible to lock or unlock device rotation in a certain situation as described in the link, and I already implemented the feature in other way.
What is left can be regenerated by the following procedure:
Set iPad in landscape mode.
Launch the app (which will force the orientation in portrait mode), without rotating the device.
When the animation is over, the device remains in portrait mode (which is odd because the device is in landscape mode).
Orientation can be fixed when user tries to rotate to portrait > landscape mode one or twice.
What I do want to do is to eliminate the step #4.

After all, it is possible to implement the feature I wanted by the following combination, without any other settings in other view controllers:
// Control device orientation only in AppDelegate.m
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
return _isFinished ? UIInterfaceOrientationMaskAll : UIInterfaceOrientationMaskPortrait;
}
- (void)onSplashAnimationEnded {
_isFinished = YES;
// Invoke OS orientation change message
[UIViewController attemptRotationToDeviceOrientation];
}
For this, device orientation should be available in other view controllers.

Related

Programmatically rotate iOS app upside down using objective-c

I want to rotate my app upside down portrait using the following code in the ViewController:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{ //return NO;
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationMaskPortraitUpsideDown);
}
- (UIInterfaceOrientationMask) supportedInterfaceOrientations
{
return [super supportedInterfaceOrientations] | UIInterfaceOrientationMaskPortraitUpsideDown | UIInterfaceOrientationMaskPortrait;
}
In the AppDelegate:
- (UIInterfaceOrientationMask) application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
return UIInterfaceOrientationMaskPortraitUpsideDown | UIInterfaceOrientationMaskPortrait;
}
When the user presses a button
NSNumber * value = [NSNumber numberWithInt:UIInterfaceOrientationPortraitUpsideDown];
[[UIDevice currentDevice] setValue:value forKey:#"orientation"];
The app does somehow not rotate and I have no idea why.
Somebody can give a hint?
Thank you
I added the orientations in the info.plist and set the checkboxes in the general settings in deployment info section.
Do I understand you correctly, that you want to programatically want to rotate the user interface, independend from the physical orientation of the device?
This is not how it works: The delegate methods (shouldAutorotate... etc.) are called by iOS when a (physical) rotation of the device is detected, e.g. the user turns it upside down. In the delegate methods you then get the chance to adopt the views to the new orientation, if you need to do so.
In the simulator, you can simulate device rotation by Alt+Left / Alt+Right keys.
You cannot rotate the orientation programatically it depends on sensors of the device. However you can rotate the layer of the view.
self.view.layer.transform = CGAffineTransformMakeRotation(M_PI_2);

iOS keep status bar in portrait

I have an app that uses the proximity sensor but the proximity sensor does not work in landscape mode. I have heard that if you keep the status bar in portrait mode it the sensor will work
I have tried this but it did not work.
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];
The status bar still switched into landscape mode.
What do I do?
If you would like to keep your app in portrait mode regardless of DeviceOrientation, I would suggest you add the following code to your viewController.
- (BOOL) shouldAutorotate{
return NO;
}
- (NSUInteger) supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait;
}
- (UIInterfaceOrientation) preferredInterfaceOrientationForPresentation{
return UIInterfaceOrientationPortrait;
}
This will ensure that your app will start in portrait mode, and stay in portrait mode, even if the device is turned.
EDIT: In order to keep the app in landscape while having just one view on portrait mode, add the above code to the one viewController you would like to restrict to portrait mode.
Add the following function to your appDelegate:
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
/* This is in order to allow views that do not support landscape mode to be able to load in
*/
return UIInterfaceOrientationMaskAll;
}
Add the following code to your other view controllers:
- (BOOL) shouldAutorotate{
return YES;
}
- (NSUInteger) supportedInterfaceOrientations{
return UIInterfaceOrientationMaskLandscape;
}
- (UIInterfaceOrientation) preferredInterfaceOrientationForPresentation{
return UIInterfaceOrientationLandscapeRight; //you can choose either landscape orientation here
}
I suggest you use this hierarchy:
RootViewController - it will contain the reference (preferably
strong) to your proximity sensor, which I recommend you run on a
background thread. This will support only portrait mode, so your
proximity sensor will work ok (I hope).
displayViewController - it will contain all the UI elements you have, and support only landscape mode
You could manage communication between both of them by using delegates
Also, after the viewDidApper of RootViewController, please use the presentViewController (iOS 6.0 and above) or presentModalViewController (iOS 5.x) selector to add the displayViewController's view on screen. Using [self.view addSubview: displayViewController.view]; will not work (I speak from personal experience).

how to force iPad to load in landscaperight orientation?

I have an iPad app that supports UIDeviceOrientationPortrait and UIDeviceOrientationLandscapeLeft.
I did include this method :
- (BOOL)shouldAutorotateToInterfaceOrientation:
(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait ||
interfaceOrientation == UIInterfaceOrientationLandscapeLeft );
}
The issue I have is that I need it to load in the UIDeviceOrientationLandscapeLeft mode, just for the load, because my UI controls will be setup properly. how can I force it only once on load.
One thing I wanna note is that this has to be min iOS 5.
I recently had similar problem, but I wanted to change from Landscape to Portrait by force, I knew in old versions there were built in methods but unfortunately we are never sure when and what is working for us, but I gave this code a try and It worked for me, but my scenario was to forcing from landscape to portrait, which is opposite to your scenario, but anyways it works, here is the code possibly for your scenario;
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
-(void)viewWillAppear:(BOOL)animated {
UIApplication* application = [UIApplication sharedApplication];
if (application.statusBarOrientation != UIInterfaceOrientationLandscapeLeft)
{
UIViewController *c = [[UIViewController alloc]init];
[self presentModalViewController:c animated:NO];
[self dismissModalViewControllerAnimated:NO];
}
[super viewWillAppear:animated];
}
EDIT working on IOS 6.1 I have added two more methods which I did not add in my previous post, I add now all what is working for my application...
- (BOOL)shouldAutorotate
{
return NO;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeLeft;
}
the idea is to check the statusbar orietnation and add and dismiss a modalViewController and it works for me to force from one to another orientation.
Even if this answer is not what you expected:
Give yourself a favor: it is really complex to force the device into a specific orientation.
You can search here on SO, what all works and does not work, and works in 6.1 and not in 6.01. and so on.
So fastest and safest is, to fix your code such that it can corectly initialize in both orientations.
Despite any app Info.plist settings or -shouldAutorotateToInterfaceOrientation: (or -shouldAutorotate) method overrides, view controllers start off in portrait and are then rotated into landscape by iOS.
What is preventing your UI layout from being setup properly?
Update in the Project Settings OR the info file.
In iOS 6.x you should override supportedInterfaceOrientations.
Try also preferredInterfaceOrientationForPresentation.

In IOS 6 on iPad, initial rotation is always portrait, after that it always rotates correctly

In a shipping app that has worked correctly under iOS 5.X and supports all orientations, built against iOS 6 it always starts in portrait even when the ipad/simulator is in landscape).
I did add the new rotation methods
- (BOOL)shouldAutorotate NS_AVAILABLE_IOS(6_0);
- (NSUInteger)supportedInterfaceOrientations NS_AVAILABLE_IOS(6_0);
but that makes no difference.
Note we do not use a navigation controller as the root view controller. Otherwise the app rotates correctly after the initial problem.
The root view controller handles all the decision making for rotations and is added to the main window as
self.window.rootViewController = viewController;
I have all the rotations in the plist key set UISupportedInterfaceOrientations~ipad
Any ideas why the initial rotation is ignored?
Under 5.1 it calls shouldAutorotateToInterfaceOrientation and willRotateToInterfaceOrientation, etc. correctly but not under 6.0. If I build against 5.1 SDK then all is well.
After talking with Apple, they claim it is a bug in Xcode 4.5 on existing projects. Either you can create a new project and re-add everything (hard to do with a big project like ours). Or add you rotation logic something like this:
- (void)viewWillLayoutSubviews
{
if ( ! afterFirstTime )
{
[self handleRotationFor:self.interfaceOrientation];
afterFirstTime = YES;
}
}
- (void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[self handleRotationFor:toInterfaceOrientation];
}
on your root view controller. I got this answer right before their break Thanksgiving week so it might be a little sketchy, but this code does work.
If your application support portrait view, as MusiGenesis said; "iPad apps always start in portrait (even if the device is landscape) in iOS 5 as well."
But i found a solution to start in device orientation.
You can set the initial rotation in the root ViewController, after viewDidLoad function as below.
The code seems to be pointless but it works.
No need to handle portrait rotation.
-(void)viewDidLoad {
[super viewDidLoad];
if ([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeLeft) {
[[UIDevice currentDevice] performSelector:NSSelectorFromString(#"setOrientation:") withObject:(id)UIInterfaceOrientationLandscapeLeft];
}
else if ([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeRight) {
[[UIDevice currentDevice] performSelector:NSSelectorFromString(#"setOrientation:") withObject:(id)UIInterfaceOrientationLandscapeRight];
}
}
Regards.

Different user interfaces for landscape and portrait orientations

I've long been a question to which I have not found a good answer.
Is it possible (it must! ;) to build different user interfaces for example the landscape and portrait or iPhone with 3,5" oder 4" display.
Like saying in code, THIS IS the landscape interface and THIS IS the portrait interface...
I hope there is a simple way to this. :)
With best regards from Munich, Germany
Laurenz
This is how I do it. I made a function called configureViewForOrientation: that takes as a parameter the orientation that you want to set up the interface for.
-(void)configureViewForOrientation:(UIInterfaceOrientation)orientation
{
if (UIInterfaceOrientationIsPortrait(orientation))
{
//set up portrait interface
}
else
{
//set up landscape interface
}
}
You can call this method from your viewDidLoad (or wherever you initially set up your interface) and feed it the current orientation using [UIApplication sharedApplication].statusBarOrientation:
-(void)viewDidLoad
{
[super viewDidLoad];
[self configureViewForOrientation:[UIApplication sharedApplication].statusBarOrientation];
}
You can also call it when your device is rotated:
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
[self configureViewForOrientation:toInterfaceOrientation];
}
There are a couple caveats (such as whether you're checking device orientation immediately upon app launch) but this should work for the majority of the time.

Resources