I'm trying to get an app working in landscape mode which I've very nearly done, but for some reason the buttons on my view aren't working (ie. they don't press). I'm using a root view controller which loads the initial view controller as follows :
- (void)viewDidLoad
{
[super viewDidLoad];
StartViewController *viewController = [[StartViewController alloc] initWithNibName:#"StartView" bundle:nil];
self.startViewController = viewController;
startViewController.delegate = self;
[viewController release];
[self.view addSubview:startViewController.view];
}
I've also set the Initial Interface Orientation value in my Info.plist file and overridden the following in my root view controller :
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return((interfaceOrientation == UIInterfaceOrientationLandscapeRight) ||
(interfaceOrientation == UIInterfaceOrientationLandscapeLeft));
//return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
The view loads fine and fills the screen in landscape mode as it should, but for some reason I just can't press any of the buttons on the view.
I'm sure it's something simple related to me using a root view controller because I've managed to get this to work fine before with an app with just a single view controller.
Can anybody help me out here?
I think the problem is somewhere in xib.
E.g. the button is placed on UIView with incorrect resize masks. So that in landscape mode the button appears outside the view, and touches can't reach the button. You can check it setting clipSubviews in all the parent view -- if I'm right, you will not see the button any more.
I had a simular problem. In my case I was subclassing a UITableViewCell and I has overwritten the layoutSubviews method. In there I was doing translations. But I forgot to put the [super layoutSubviews]; before my implementation. After I put it htere, the button were working again in landscape mode. It was strange that in portrait it worked and in landscape not.
Related
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'm trying to only support landscape. There's a new requirement to show this dialog box that explains some things about our app the first time. So in my first view controller that gets launched, in viewDidLoad, I have this code:
BOOL showFirstTimeUse = [[NSUserDefaults standardUserDefaults] boolForKey:#"ShowFirstTimeUse"];
if (!showFirstTimeUse) {
FirstUseViewController *tvc = [[FirstUseViewController alloc] initWithNibName:#"FirstUseViewController" bundle:nil];
tvc.modalPresentationStyle = UIModalPresentationFormSheet;
tvc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:tvc animated:YES];
[tvc release];
}
Then in the FirstUseViewController, I have this defined:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return UIInterfaceOrientationLandscapeLeft | UIInterfaceOrientationLandscapeRight;
}
In IB, I have not changed any of the default settings. I basically just dropped a UIWebView to the upper left hand side of the screen to show my data and connected an outlet to it so I can show formatted text easily.
When I run my app now, the presentation of this view controller causes my app to start in portrait rather than landscape. How do I fix this? Thanks.
Your implementation of shouldAutorotateToInterfaceOrientation: is faulty; It will always evaluate true. You likely want to use:
return UIInterfaceOrientationIsLandscape(interfaceOrientation);
I'm new to StackOverflow, and also new to objective-c.
I have tried looking for a couple weeks now to find something that gives me a hint of what to do, but I can't seem to get through this one without asking a question. It feels like it should be simple, but...
I'm having a problem with the rotation of a "rootView" controller. It should show up in landscape (which it did, before I decided to use a navigation controller). The simulator shows up in the correct orientation, but it has loaded the view rotated 90 degress left, so that the text reads from bottom to top, sideways, so you have to cock your head left. The leftmost portion of the view is visible, but the remainder of the view runs off the top of the screen. It's a large program (I'm finding that, in general, with objective-c, but enjoying it nonetheless...), but here's the gist of what I think are the important code areas:
In the appDelegate, I create a window, my rootViewcontroller, and the navcontroller:
// .h file:
UIWindow *window;
wordHelper3ViewController *viewController;
UINavigationController *navigationController;
Then in the implementation:
//.m file
- (BOOL)application:(UIApplication *)applicationdidFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Hide status bar
application.statusBarHidden = YES;
// --- Add the view controller's view to the window and display.
[window addSubview:viewController.view];
[window addSubview:navigationController.view];
[window makeKeyAndVisible];
return YES;
}
Then I release all of these in the dealloc.
In my root view, I'm doing this:
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
if (interfaceOrientation == UIInterfaceOrientationLandscapeRight){
return YES;
} else {
return NO;
}
}
I implemented the following, to see what was happening, and I'm getting the log message on startup immediately:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{
if (fromInterfaceOrientation == UIInterfaceOrientationLandscapeLeft || fromInterfaceOrientation == UIInterfaceOrientationLandscapeRight) {
NSLog(#"didRotate...");
}
}
Other than this, I don't think I'm doing anything in my code that should affect the view(s). So now, on to InterfaceBuilder:
In the attributes inspector for both the rootView and the navigation controller, the orientation is set to landscape. For the rootView, under referencing outlets, the “view” is set to file's owner. I also have an action attached to the view (touchUpInside) – I changed its class to UIButton, because I wanted to resignFirstResponder when the user clicks anywhere in the background.
For the navigationController, under Referencing outlets, it shows a connection from the navigationController to my appDelegate.
In the main window xib, the nav contoller shows up in the list, and the view controller shows up as a subview of it.
The viewcontroller also shows up on its own, in the main window's list of objects.
The only thing that stands out to me, is that when I double click the window object, IT comes up visually in portrait mode.
Does anyone have any ideas?
If you want the startup orientation to be different from the initial Portrait mode, you need to edit your info.plist file. Add an entry for "intial interface orientation" and set the value that you want.
Here's a screenshot:
If you want to rotate a UINavigationController, it will take a bit more work. See this similar question for more information.
I think your problem is that you are adding your navigation controller as a subview to the window and orientation notifications are only sent to the first subview in "window".
Try this instead.
//.m file
- (BOOL)application:(UIApplication *)applicationdidFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Hide status bar
application.statusBarHidden = YES;
// --- Add the view controller's view to the window and display.
[window addSubview:viewController.view];
[viewController.view addSubview:navigationController.view];
[window makeKeyAndVisible];
return YES;
}
Its annoying, but I've resolved orientation problems by only every having one subview in "window" and then controlling everything through that one subview (in this case viewController)
Forgive me if I'm misunderstanding, but shouldn't this
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
if (interfaceOrientation == UIInterfaceOrientationLandscapeRight){
return YES;
} else {
return NO;
}
}
really be this
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
?
So I have a modal view displaying in my app that has a little info for the user to fill out. The problem is that when the device is rotated, some animation occurs, but only in the frame. The form itself does not rotate. All the autorotate options are set to YES. I am displaying it when the user clicks on a field in a popover. This makes me suspect it has something to do with that but I am not sure. It is bizzare because if the device is in either view and then the modal window is displayed, it is fine. It only happens when the device is rotated in the modal view. Does anyone have any idea what may be causing this behavior when the device is rotated? Thanks!
Here is a snippet that is handled in the popover view controller:
if (currentLevel == 1 && businessOrLocation == 0){
if(tbsViewController == nil)
tbsViewController = [[BusinessFilteredViewController alloc] initWithNibName:#"BusinessFilteredView" bundle:[NSBundle mainBundle]];
NSMutableArray *tempBusiness = [[NSMutableArray alloc] init];
for (id theKey in appDelegate.groupedBusiness) {
NSMutableArray *tempArr = [appDelegate.groupedBusiness objectForKey:theKey];
[tempBusiness addObject:tempArr];
}
tbsViewController.businessOrLocation = businessOrLocation;
tbsViewController.modalPresentationStyle = UIModalPresentationFullScreen;
tbsViewController.modalTransitionStyle = UIModalPresentationFullScreen;
[self presentModalViewController:tbsViewController animated:YES];
}
I ran into this problem as well. The fundamental problem is that popover controllers cannot present modal views—it seems that case wasn’t properly considered or designed for. In my situation, it was easy enough to work around. I just extended the delegate protocol for my popover-hosted view controller. The main view sets itself up as the delegate to the popover view, and takes responsibility for displaying and dismissing the modal views the user requests from within the popover.
Since I already had a delegate protocol to cleanly dismiss the popover view when the user clicks “done” it was only a small stretch to get autorotation working the way I wanted it to. Here are some snippets:
#protocol InfoViewControllerDelegate <NSObject>
#optional
// Implement this to close the info view once the user clicks done.
- (void)infoViewDidFinish:(InfoViewController *)view;
// Implement this method if the delegate launched us as a popup view and must therefore
// take responsibility for diplaying help.
- (void)infoViewDidRequestHelp:(InfoViewController *)view;
#end
And in my main iPad view which presents this popup view:
#pragma mark - InfoViewControllerDelegate methods
- (void)infoViewDidFinish:(InfoViewController *)view {
[self hideInfo:self];
}
- (void)infoViewDidRequestHelp:(InfoViewController *)view {
[self hideInfo:self]; // Close the info view first
HelpViewController *help = [[HelpViewController alloc] init];
help.delegate = self;
[self presentModalViewController:help animated:YES];
[help release];
}
To make life simple for cases where I am launching the info view outside of a popup view (for example, on the iPhone, it is a simple modal view), it checks to see if the delegate handles the modal subviews, and if not, handles them itself. That way I didn’t need to change the iPhone base controller at all, since autorotation already worked fine there. Here’s the “Help” button action in the info view controller, showing how I did that:
- (IBAction)help:(id)sender {
if ([delegate respondsToSelector:#selector(infoViewDidRequestHelp:)]) {
[delegate infoViewDidRequestHelp:self];
} else {
HelpViewController *help = [[HelpViewController alloc] init];
help.delegate = self;
[self presentModalViewController:help animated:YES];
[help release];
}
}
With this code in place, my entire interface autorotates smoothly on both devices, whether or not popup views were involved.
Just so i understand correctly... You are displaying a popover and inside that popover if the user taps a certain element then you are displaying a full screen modal view controller? Vie never tried that before and it seems odd for two reasons.
First it seems jarring to the user in my opinion. The popover gives you a nice, integrated UI and the modal takes you away.
More importantly though, your popover view controller doesn't really have authority over the whole screen so presenting a full screen modal from a popover just seems inherently wrong.
I would suggest you display a nav controller in the popover controller and instead of presenting the new view controller modally over the whole screen just push it on to the nav controller in the popover and keep the user inside the popover.
If that doesn't really work for you, then I would suggest reviewing your UI needs and redesigning the layout.
I am guessing that you implemented - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation in BusinessFilteredViewController and returns YES
Could you check that you add more than 1 subviews to application window . If so, try to create container UIViewController for all viewControllers that you want to add to window.
I am working on an app (my first one), which is basically a TabBar app.
To be more precise there are:
- a login view controller
- a tab bar controller (when login is done)
- a landscape view controller that is used when the first itel of the TabBar is switch from Portrait to Landscape.
So, when I am in the first tab, I need to be able to move to landscape view to display some other data. In my tab bar controller, I have implemented those methods:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if([self selectedIndex] == 0)
return YES;
return NO;
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
// Get AppDelegate
MyAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
if (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
// Remove TabBarView and add graph Landscape View
[self.view removeFromSuperview];
[delegate setSubViewLandscapeViewController];
}
}
In the delegate, I have implemented the setSubViewLandscapeViewController and the setSubViewTabBarController:
- (void)setSubViewTabBarViewController {
[window addSubview:[tabBarController view]];
}
- (void)setSubViewGraphLandscapeViewController {
[window addSubview:[landscapeViewController view]];
}
I want the landscapeViewController to display only in landscape mode, I have then (in my landscapeViewController):
- (void)viewWillAppear:(BOOL)animated {
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];
}
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
NSLog(#"willRotateToInterfaceOrientation");
}
A part of this works fine, I mean the switch from portrait to landscape is ok (when I am in the first tab), the tabbarcontroller is remove from the SuperView and the landscape view is added as a subview instead.
The thing is... I do not know how to switch back to portrait mode (and then load the previous controller, the tabBar one using the setSubViewTabBarViewController of my delegate). It seems none of the willRotateToOrientation, willRotateFromOrientation, .. are triggered when I actually move the device from the landscape view...
In short, when I am in the landscape view I do not know what to do to move back to the tabbar view... I am kind of stuck in the landscape view once I am in this one.
Thanks a lot for your help,
Luc
Look at the pie chart in CPTestApp-iPhone in the examples folder. It handles rotation by implementing -(void)didRotateFromInterfaceOrientation: and resizing the graph after a rotation.
Well, I managed to get a solution for this problem.
In fact, while moving from portrait to landscape I removed the tabbarcontroller from window subview and add the landscapeviewcontroller instead.
It seems it was not the correct thing to do.
Instead, I add the landscapeViewController as subview of the tabbarcontroller and remove it when going from landscape to portrait.
I still have a problem however with the y position of the landscape view which seems to changes when I do several decive rotation in a row....
Regards,
Luc