What i have:
i have a viewcontroller that supports Portrait and landscape. When in landscape i show a filter view for the content of the portrait.
What i need to do:
When the user selects a filter in the landscape view i want to force rotate the device back to portrait.
I have done some Googling and discovered
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait];
This is a private API and i dont want to do that. (But excatly what i am after)
In short - on user action i want to force rotate the device.
Is there something i am missing from the docs?
Any ideas would be super.
Dan
Learned this from experience! Do this in your viewDidLoad::
UIViewController *vc = [[UIViewController alloc] init];
[self presentModalViewControllerAnimated:NO];
[self dismissModalViewControllerAnimated:NO];
It will force landscape, provided you return YES for shouldAutorotateToInterfaceOrientation for only landscape. No private APIs!
You can try with this If works.
-(void)forceFullyPortraitView{
[self.appDel.navigationController.view removeFromSuperview];
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait];
[ [UIApplication sharedApplication].self.delegate.window addSubview:self.appDel.navigationController.view];
self.navigationController.navigationBar.hidden=NO;
}
-(void)forceFullyLandscapeView{
[self.appDel.navigationController.view removeFromSuperview];
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight];
[ [UIApplication sharedApplication].self.delegate.window addSubview:self.appDel.navigationController.view];
self.navigationController.navigationBar.hidden=NO;
}
You can set landScepe right or left.
Related
I am calling a UIImagePickerController (sourceTypeCamera) as a modalViewController from my MainViewController.
However, the UIImagePickerController doesn't fill the screen on top, as the image attached shows.
Any idea what can be causing this, and how to fix?
After lots of tries, I discovered that calling presentViewController from the [[[[UIApplication sharedApplication] delegate] window] rootViewController] solved the problem.
You should change the frame property of imagePickerController. when intializing I.e.
imagePickerController.view.frame.origin.y = 20;
Some code would be helpful.
If relevant, try setting the bounds property instead of the frame property.
In my application in a viewcontroller which is inside navigationController - i'm doing simply like this:
UIImagePickerController* imagePickerController_;
imagePickerController_.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentModalViewController:imagePickerController_ animated:YES];
and
#interface CustomViewController : UIViewController <UIImagePickerControllerDelegate>
Works without problems. If You still have problems, then can you please share some code? what kind of navigation structure your application have (tabbarcontroller, navigationcontroller, .. ?)?, how do you present imagepickercontroller?
There is a boolean on UIViewController that may be of use to you: wantsFullScreenLayout. According to the docs, this is:
A Boolean value indicating whether the view should underlap the status bar.
I've had several issues, especially on iOS 5, with views underlapping the status bar, especially when presented modally. The best thing I have found is to set this value to YES, and manually lay out your view below the status bar. FYI, the status bar has a height of 20.
Call
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationNone];
Before calling
[self presentModalViewController:picker animated:YES]
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
[self.view addSubview:imagePicker.view];
[imagePicker viewWillAppear:YES];
[imagePicker viewDidAppear:YES];
[[UIApplication sharedApplication] setStatusBarHidden:NO animated:NO];
Hi I'm using following code to show my app's login screen.
LoginViewController * loginController = [[LoginViewController alloc] initWithNibName:#"LoginViewController" bundle:nil];
UINavigationController * navController = [[UINavigationController alloc] initWithRootViewController:loginController];
navController.modalPresentationStyle = UIModalPresentationFormSheet;
[self.navigationController presentModalViewController:navController animated:YES];
Its loading properly. Here my problem is my app should be in landscape mode only. Here I'm using UIModalPresentationFormSheet so app is automatically appearing in portrait mode. I would like to force my app to change to landscape mode after this login view loads. some one please help me how to rotate my view into landscape mode after this UIModalPresentationFormSheet loads. (It means in LoginViewController's viewDidLoad mode I have to force my app to change to landscape mode. How can I achieve that). Thanks in advance
Try re-writing your User Interface Frame attributes with landscape co-ordinate values.
Do this in
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
duration:(NSTimeInterval)duration
and with the proviso
[super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft
|| toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)
I want all view controllers to support only portrait mode, except one view controller lets call it "LandscapeSupportViewController" that should support also landscape mode.
The problem is when I'm in LandscapeSupportViewController in landscape mode and then push a new view controller that only support portrait mode, the pushed view controller will be in landscape mode also! How could I force it to be portrait?
I saw few apps that do it, take for example Skype iPhone app, the Messages tab is portrait only -> then if you press to enter the message itself you get a view controller that support landscape also because it make sense to enable landscape mode when user is chatting -> then if you press to view the persons profile, a new view controller will be pushed but in portrait! the same happen if you go back, you will forced to return to portrait even if you came from landscape...
Thanks
I'd had students try to accomplish exactly what you are trying to accomplish, and after much research, the general consensus is: this is a bad idea and requires a lot of (App Store legal) hacks to accomplish, and still doesn't turn out too pretty (status bar, for example, screws up). You'll notice in the Skype app that when you go into the IM section, rotate to landscape, and hit back, the UI "snaps", or sort of gets instantly reloaded.
This is not a good user experience, and I'd recommend rethinking your design to be more in line with what Apple recommends.
If i got you correctly you want to change device orientation in some conditions.
[[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationPortrait animated:NO];
set your own orientation using above line, just put this lines inside the if condition. condition is depends on you.
Thank you!!
Write this lines before you push viewController which supported only portrait From landscapeViewController
[appdel.navigationController.view removeFromSuperview];// This navcontroller used with rootviewcontroller
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait];
[ [UIApplication sharedApplication].self.delegate.window addSubview:appdel.navigationController.view];
self.navigationController.navigationBar.hidden=NO;
Here is a solution.
You can add a category for UINavigationController which manages the view controller orientation. See code below:
#interface UINavigationController (MyViewOrientations)
#end
#implemetation UINavigationController (MyViewOrientations)
- (BOOL)supportLandscapeModeForViewController:(UIViewController *)controller {
return [controller isKindOfClass:[LandscapeSupportViewController class]]
}
- (NSUInteger)supportedInterfaceOrientation {
UIViewController *controller = [self visibleViewController];
NSUInteger orientationMasks = UIInterfaceOrientationMaskPortrait
if([self supportLandscapeModeForViewController:controller]) {
orientationMasks |= UIInterfaceOrientationMaskLandscapeLeft;
orientationMasks |= UIInterfaceOrientationMaskLandscapeRight;
}
return orientationMasks;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
UIViewController *controller = [self visibleViewController];
if([self supportLandscapeModeForViewController:controller]) {
return UIInterfaceOrientationLandscapeLeft; // Your call
}
else {
return UIInterfaceOrientationPortrait;
}
}
- (BOOL)shouldAutorotate {
UIViewController *controller = [self visibleViewController];
return [self supportLandscapeModeForViewController:controller];
}
#end
If the situation is more complex, different views support different orientations. You can override "supportedInterfaceOrientation", "preferredInterfaceOrientationForPresentation", "shouldAutorotate" in your view controllers, and delegate calls from UINavigationController category code with "visibleViewController".
I am running an "iPhone-only" app in the iPad simulator...When the orientation of the device is changed to landscape mode, I have a view controller that kicks in and programmatically loads a WebView. This works swimmingly in the iPhone (no gap on top of landscape view), but when simulating in the iPad, there's a 20px (I think?) gap at the top of the view.
Here's the code in the landscape view controller's viewDidLoad where I load the WebView:
[super viewDidLoad];
// Initialize webview and add as a subview to LandscapeController's view
CGRect webFrame = [[UIScreen mainScreen] bounds]; // Use bounds to take up entire screen
self.myWebView = [[[UIWebView alloc] initWithFrame:webFrame] autorelease];
self.myWebView.scalesPageToFit = YES;
self.myWebView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
self.myWebView.delegate = self;
[self.view addSubview: self.myWebView];
// remove status bar from top of screen
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackOpaque];
Setting the status bar to default, has no influence.
I can't seem to figure out why this would be fine on the iPhone, but emerge on the iPad???
Any ideas? Thanks in advance!
The screen bounds are in screen coordinates. You're adding the webview as a subview of self.view; its frame is in self.view coordinates. You want to fill your view, not the screen (your view is automatically resized by UIViewController/the rest of UIKit, which should end up resizing the web view to to auto-resizing):
self.myWebView = [[[UIWebView alloc] initWithFrame:self.view.bounds] autorelease];
It's not safe to change the status bar in -viewDidLoad. View-loading can happen anywhere (it happens when anything calls viewController.view). I'm also not sure why you're setting the style; you want to set hidden-ness:
In -viewWillAppear:, do [application setStatusBarHidden:YES animated:animated];
In -viewWillDisappear:, do [application setStatusBarHidden:NO animated:animated];
Finally, you might be seeing different behaviour because the iPad is running OS 3.2.x and the phone is running 3.1.x or 4.x. Additionally, the iPhone-compatibility mode uses a dummy status bar; the "real" status bar always stays at the edges of the screen.
20 pixels at the top is almost always invariably related to the height of the status bar.
The code you posted looks fine... for setting up the UIWebView. But you're adding it as a subview to your view controller's view. How is that sized? What is its frame?
I finally figured this out. The key missing component, which I didn't mention in the original post, is that the view controller that manages landscape is actually implemented as a modal view. (See the View Controller User Guide for code on how to do this) In concept, I have a Portrait view controller. (which is the primary controller) In the Portrait view controller's viewDidLoad I apply for a Notifier that is triggered off of a change in the orientation like so:
- (void)viewDidLoad {
[super viewDidLoad];
// SECTION to setup automatic alternate landscape view on rotation
// Uses a delegate to bring the landscape view controller up as a modal view controller
isShowingLandscapeView = NO;
// Create Landscape Controller programmatically
self.landscapeViewController = [[LandscapeViewController alloc] initWithNibName:#"LandscapeViewController" bundle:[NSBundle mainBundle]];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(orientationChanged:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
// END SECTION landscape modal view controller
Then, when orientation changes this method is called:
- (void)orientationChanged:(NSNotification *)notification
{
UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
if (UIDeviceOrientationIsLandscape(deviceOrientation) && !isShowingLandscapeView)
{
// Load Landscape view
landscapeViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:self.landscapeViewController animated:YES];
isShowingLandscapeView = YES;
}
At the same time I was removing the status bar from the Landscape view controller's viewWillAppear method:
- (void)viewWillAppear:(BOOL)animated
{
// remove status bar from top of screen
[[UIApplication sharedApplication] setStatusBarHidden:YES animated:animated];
self.myWebView.delegate = self; // setup the delegate as the web view is shown
}
and this is where the problem is introduced. The Portrait view controller captures the screen dimensions, before transitioning to landscape as a Modal View. Then, viewWillAppear, in the Landscape view controller, removes the status bar.
So, the solution is to move the
[[UIApplication sharedApplication] setStatusBarHidden:YES animated:animated];
statement to the orientationChanged method in the Portrait view controller, BEFORE transitioning to the Landscape Modal View.
- (void)orientationChanged:(NSNotification *)notification
{
UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
if (UIDeviceOrientationIsLandscape(deviceOrientation) && !isShowingLandscapeView)
{
// remove status bar from top of screen
// NOTE: this must be declared BEFORE presenting the Modal View!!!! If it's not, the landscape view will
// contain an ugly white bar in place of the missing status bar at the top of the view.
[[UIApplication sharedApplication] setStatusBarHidden:YES];
// Load Landscape view
landscapeViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:self.landscapeViewController animated:YES];
isShowingLandscapeView = YES;
}
Note, that as tc helpfully mentioned above, if you want the status bar to appear when orienting back to Portrait, then you need
[[UIApplication sharedApplication] setStatusBarHidden:NO animated:animated];
in the viewWillDisappear method in the Landscape view controller.
Here is my problem:
- I have one navcontroller and inside it one tabbar controller with 4 view controller.
- I want to add following functionality:
- On landscapeRight to dismiss navcontroller, tabbar controller and everything and load whole new controller - this one goes ok, here is the code:
- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
// Just delete the lines for the orientations you don't want to support
if(toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) {
[appDelegate ToHorizontalAverageResponseView:self];
}
return YES;
}
Here is the code in the App Delegate:
- (void)ToHorizontalAverageResponseView:(id)sender
{
HorizontalResponseViewController *tempController = [[HorizontalResponseViewController alloc] initWithNibName:nil bundle:nil];
[self setHorizontalResponseViewController: tempController];
[tempController release];
//[UIApplication sharedApplication].statusBarOrientation = UIInterfaceOrientationLandscapeRight;
// View rotation transformation
CGAffineTransform landscapeTransform = CGAffineTransformMakeRotation( M_PI * 90.0 / 180.0 );
[[horizontalResponseViewController view] setTransform:landscapeTransform];
[window addSubview:[horizontalResponseViewController view]];
}
The question is how to transfer back to portrait view and all those navbar and tabbar controllers?
Thx,
Mladen
It sounds like you are trying to build something along the lines of the iPod-CoverFlow transition. The question (on how to build the coverflow effect) was asked in Stanford's CS193P lecture and the answer hinted in the following direction:
If you can afford the memory overhead, it may be the best thing to add a new landscape view on top of all the portait views (not discarding them as you suggest). The user then interacts with this landscape view as desired until going back to portrait. All this time, the portrait views remained quietly in the background.