Is there any easy way to manually set the orientation of an interface? I need to set the interface to portrait even though the device orientation might be in landscape during loading. Kinda want to stay away from CGAffineTransforms.
One method I know that works for me (and is a bit of a hack and can display one orientation before changing to the orientation you want) is:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
UIApplication* application = [UIApplication sharedApplication];
if (application.statusBarOrientation != UIInterfaceOrientationPortrait)
{
UIViewController *c = [[UIViewController alloc]init];
[self presentModalViewController:c animated:NO];
[self dismissModalViewControllerAnimated:NO];
[c release];
}
}
First, set your app and views to only support portrait, then use this category method taken from my refactoring library, es_ios_utils:
#interface UIViewController(ESUtils)
// Forces without using a private api.
-(void)forcePortrait;
#end
#implementation UIViewController(ESUtils)
-(void)forcePortrait
{
//force portrait orientation without private methods.
UIViewController *c = [[UIViewController alloc] init];
[self presentModalViewController:c animated:NO];
[self dismissModalViewControllerAnimated:NO];
[c release];
}
#end
The view, dismissed before the frame completes, won't be displayed.
override this to control the orientation until loading...
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
Related
I have implemented this code in AppDelegate.m
-(UIInterfaceOrientationMask) application:(UIApplication *)application supportedInterfaceOrientationsForWindow :(UIWindow *)window
{
UIViewController *currentVC = [(UINavigationController *)[UIApplication sharedApplication].delegate.window.rootViewController topViewController];
if ([currentVC isKindOfClass:[VideoPlayerVC class]])
{
return UIInterfaceOrientationMaskAll;
}
return UIInterfaceOrientationMaskPortrait;
}
and pushing to the VideoPlayerVC with link like this :
NSURL *link = [NSURL URLWithString:strUrl];
VideoPlayerVC *vc = [[VideoPlayerVC alloc] init];
vc.videoUrl = link;
[self.navigationController pushViewController:vc animated:false];
This allows me to enable autorotate in the VideoPlayer ViewController but when the video playback ends in Landscape mode, the entire app is being converted into Landscape view mode only.
Please help me guys to fix the issue.
Thanks in advance.
The system only tries to invalidate your orientation when a full screen modal presentation happened or dismissed. So I suggest you to replace your [self.navigationController pushViewController:vc animated:false]; with [self presentViewController:vc animated:YES completion:nil];
And if your UE needs the navigation transition, you can try to mimic it with UIViewControllerContextTransitioning customization.
Also there is a tricky method if you must use push behavior(It's the only one method not using private api as I know)
Every time you push/pop from the navigation stack, call the code below:
[[vc presentViewController:[UIViewController new] animated:NO completion:^(BOOL completed){
[vc dismissViewControllerAnimated:NO completion:nil];
}];
The code try to make an invisible vc and dismiss it immediately to make iOS update the supported orientation.
Sir,
I am working on the mapview module which landscape is the only orientation allowed but others for portrait only. When it comes to running on device ios 7 and 8 , the view controller is still presented as portrait orientation unless I have to manually turn the device to landscape . Would you please tell me what other steps to do ?
The below is my code
AppDelegate.h
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (nonatomic) BOOL isTaskPoint;
#end
AppDelegate.m
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (UIInterfaceOrientationIsPortrait(interfaceOrientation)) return YES;
return NO;
}
PreviousController.m
MapViewController * sliderVC = [[MapViewController alloc] init ];
AppDelegate *appDelegate = (AppDelegate *) [UIApplication sharedApplication].delegate;
appDelegate.isTaskPoint = TRUE;
sliderVC.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentViewController:sliderVC animated:NO completion:nil];
sliderVC.view.backgroundColor = [UIColor clearColor];
// MapSwift maps =
MapViewController.h
- (void)bannerTapped:(UIGestureRecognizer *)gestureRecognizer {
AppDelegate *appDelegate = (AppDelegate *) [UIApplication sharedApplication].delegate;
appDelegate.isTaskPoint = FALSE;
[self dismissViewControllerAnimated: NO completion:nil];
}
MapViewController
- (BOOL) shouldAutorotate {
return YES;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationLandscapeRight;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight|| interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}
There is one trick that really works.
You can access the status bar and set its orientation. That becomes active next time a view is displayed modally.
However, right after displaying modally you can remove the modally displayed veiw controller. When you do that within the same method, then the user would not noticing anyhing.
Now the device has the desired orientation. You can now safely push the view controller that you want to be in another orientation.
Do not forget to rotate it back, when returning from that view controller!
See the answer to this question. It comes with some code sniplets. Force controllers to Change their orientation in Either Portrait or Landscape
If you want to disable or enable specific orientation in some view controller then this might be helpful to you.
And if you want to open some view in specific orientation then use this in viewDidLoad
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationPortrait];
[[UIDevice currentDevice] setValue:value forKey:#"orientation"];
I have a single view app with 2 view controllers to present different layouts for portrait and landscape. I have set up the orientation changed notifications and can successfully display the landscape view on the first orientation change.
1st Problem:
When I change the orientation back to portrait the portrait view is not displayed.
2nd Problem:
When I change the orientation back to landscape the landscape view displays but I get a warning:
Attempt to present CalculatorViewControllerLandscape on CalculatorViewController whose view is not in the window hierarchy.
I have been through the apple documentation and several posts with similar problems and have figured out that the answer lies in the use of delegation but I have not been able to get delegation set up correctly. Here is my attempt:
CalculatorViewControllerLandscape.h
#protocol SecondControllerDelegate <NSObject>
#end
.....
#property(nonatomic, weak) id <SecondControllerDelegate> delegate;
CalculatorViewController.h
#interface CalculatorViewController : UIViewController <SecondControllerDelegate> {
....
}
#property (strong) CalculatorViewControllerLandscape *landscapeVC;
CalculatorViewCalculator.m
- (void)awakeFromNib
{
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(orientationChanged:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
// register as a delegate
self.navigationController.delegate = (id)self;
}
- (void)orientationChanged:(NSNotification *)notification
{
UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
if (UIDeviceOrientationIsLandscape(deviceOrientation) &&
!isShowingLandscapeView)
{
NSLog(#"Orientation has changed to landscape");
// code here to show landscape storyboard
UIStoryboard *landscapeStoryboard = [UIStoryboard storyboardWithName:#"LandscapeStoryboard" bundle:nil];
UIViewController *landscapeViewController = [landscapeStoryboard instantiateInitialViewController];
[self presentViewController:landscapeViewController animated:YES completion:nil];
isShowingLandscapeView = YES;
}
else if (UIDeviceOrientationIsPortrait(deviceOrientation) &&
isShowingLandscapeView)
{
NSLog(#"Orientation has changed to portrait");
[[self presentingViewController] dismissViewControllerAnimated:NO completion:nil];
isShowingLandscapeView = NO;
}
}
I've been working on this for several hours and have checked all posts which similar problems but I still can't figure it out. Thanks in advance for help.
Best practice is to handle rotation events in a single UIViewController, rather than using two separate ones. I'm not familiar with interface builder, but programmatically you can override -(void)viewWillLayoutSubviews; and lay out your view appropriately based on self.interfaceOrientation. I recommend you do it that way.
However, in answer to your question:
try changing
[[self presentingViewController] dismissViewControllerAnimated:NO completion:nil];
to
[self dismissViewControllerAnimated:NO completion:nil];
This may fix the 2nd problem as well, because the old landscape view controller not being properly dismissed.
I have one view controller, named AViewController. There is a button in AViewController. When the button is clicked, i will present another view controller,lets called BViewController. If AViewController is in portrait-orientation, it works well.If the orientation is in landscape, then the BViewController is still initialized in portrait but presented in landscape.
This is the problem. I wonder how can i init BViewController in current orientation. I use [UIScreen mainScreen].bounds in the BViewController's init. but the bounds is not in landscape if the device is in landscape. I know pass the frame from AViewController to BViewController, it may work. but i don't think this is a good solution. So is there any better ways?
the function to present BViewController is as follows:
- (void)BtnClicked
{
BViewController *bvc = [[BViewController alloc] init];
bvc.delegate = self;
bvc.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:movie animated:YES completion:nil];
}
I still don't know how to do it efficiently. But i use one solution to call the willAnimateRotationToInterfaceOrientation method manually in viewDidAppear.
the snippet is as follows:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self willAnimateRotationToInterfaceOrientation:[UIApplication sharedApplication].statusBarOrientation duration:0];
}
In my IOS app, when I open the camera I have placed an image over the camera view. It looks good in portrait mode. But when it is changed to landscape mode it looks some odd. So I want to lock the UIImagePickerController in Portrait mode.
Following is my code for ui image picker controller
UIImagePickerController *imgPkr = [[UIImagePickerController alloc] init];
imgPkr.delegate = self;
imgPkr.sourceType = UIImagePickerControllerSourceTypeCamera;
How it can be locked in portrait mode....
Or, you can subclass the UIImagePickerController:
Create a new UIImagePickerController class and just add these lines to it.
- (BOOL)shouldAutorotate{
return NO;
}
Import it to the class that uses the camera and instead of using default UIImagePickerController, use the class that you created.
Your camera itself should stop from auto rotating.
This is not the best solution, but it works:
AppDelegate *appDelegate = (AppDelegate *) [[UIApplication sharedApplication] delegate];
[appDelegate.window addSubview:cameraOverlay];
imgPicker.cameraOverlayView = appDelegate.window.superview;
The camera on the background still rotates, but your overlay view doesn´t.
Hope it works for you
The only solution that worked for me was the category, but I had to add another method too:
#import "UIImagePickerController+NoRotate.h"
#implementation UIImagePickerController (NoRotate)
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
#end
Cheers!
You don't have to "lock the UIImagePicker Controller in Portrait mode".
As you said "when it is changed to landscape mode it looks some odd"
Actually I don't know why you say it look odd.
But, here is my experience of UIImagePicker view look odd in landscape mode.
That is:
When AViewController as the root view controller.
And BViewController's view add subview to AViewController's view.
And presentModalViewController:UIImagePickerController in BViewController.
The UIImagePicker view will look odd in landscape mode.
The solution to this problem is set the UIImagePickerController as the root view controller before presentModelViewController.
The source code below show the detail:
- (void) onCameraButtonTapped:(UIBarButtonItem *)buttonItem
{
//backupRootController it's use as a backup, it will recover after close the image picker controller.
self.backupRootController = [[UIApplication sharedApplication] keyWindow].rootViewController;
UIImagePickerController * imageController = [[UIImagePickerController alloc] init];
imageController.sourceType = UIImagePickerControllerSourceTypeCamera;
imageController.delegate = self;
....
[[[UIApplication sharedApplication] keyWindow] setRootViewController:imageController];
[self presentModalViewController:imageController animated:YES];
[imageController release];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
[[[UIApplication sharedApplication] keyWindow] setRootViewController:self.backupRootController];
....
}
I hope this solution can help other person in the future.
--Goman
Add a category on UIImagePickerController and override it's shouldAutoRotateToInterfaceOrientation method, as follows:
#implementation UIImagePickerController (NoRotate)
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
Just write this code in your view controller
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations.
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
-(BOOL)shouldAutorotate {
return NO;}
Try this in your view controller. This worked for me.
Note: This is for ios6.0 and above
there is no need to create a subclass, just create a category for uiimagepickercontroller and put this line on it
- (BOOL)shouldAutorotate{
return NO;
}