I am writing an iPad application using MonoTouch, MonoDevelop and Interface Builder, and i've stumbled across a problem that I can't seem to solve. It is probably something simple. What I am trying to do is force an application to Landscapemode from start. The application starts in Landscape, but doesn't resize the subviews correctly.
Basically what I am doing in my appdelegate is that I add a SubView called IndexViewController.xib to Window. In IndexViewController I have a View with a Label on it, if I then in IndexViewController override the ShouldAutorotateToInterfaceOrientation to return this: it works correctly.
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
return ((toInterfaceOrientation == UIInterfaceOrientation.LandscapeLeft) || (toInterfaceOrientation == UIInterfaceOrientation.LandscapeRight));
}
However, I now try to create a NavigationController and add it to the IndexController.xib-view on the Initialize:
void Initialize ()
{
this.View.AddSubview (NavController.View);
}
It rotates correctly but doesn't fill the entire "window", I have posted a screenshot and a sample solution. And my info.plist is set to allow "UIInterfaceOrientationLandscapeLeft" and "UIInterfaceOrientationLandscapeLeftRight" as UISupportedInterfaceOrientations
Screenshot
Sample solution here
There is probably something dead simple simple that I am missing, but I can't figure it out.
I'd say this may be due to the fact the way you're building the app's hierarchy isn't the suggested way of doing so. While you could carry on this way, you'll encounter more problems down the road.
Ideally you want to be adding the NavigationController's View the window rather than the having the NavigationController contained within a UIViewController.
In the app delegate, I would do something along the lines of:
IndexViewController indexVC = new IndexViewController()
UINavigationController navController = new UINavigationController(indexVC);
window.AddSubview(navController.View);
This will add the navigation controller's view to the window, with the RootViewController of the NavigationController being your IndexViewController
You should also remove the UINavigationController that is added to your IndexViewController in Initialise().
I just downloaded your sample solution and tried this very quickly and it loaded the app in Landscape with the view fully filling the screen. It didn't auto rotate, but this'll certainly be a good starting point for you :)
Related
I have an app with an animated splashscreen and a main interface.
To transition from the splashscreen to the main interface I used this code:
presentViewController(mainViewController, true) {
UIApplication.sharedApplication.keyWindow.rootViewController = mainViewController
}
But apparently this method ruins autorotation (took me a while to find that one). Now I have the issue that this autorotation is not with animation.
I guess this is not with animation because the old viewcontroller still lives below the other viewcontroller and it just forwards the new orientation.
How can I properly transition from one viewcontroller to the next while being able to destroy the old viewcontroller and keep rotation?
Edit: I noticed that my homescreen rotates when I close my app (from its startup orientation to the orientation the app was in when I closed it)
In addition to what Kemal said, I have found my specific issue:
I don't really understand why this gives that problem. I have a storyboard that is set in the Info.plist as the main interface (I ignored this, because I don't need it). In my AppDelegate.finishedLaunching I create a new window and set its root view controller, which I then set as key window. Removing either the window setting in AppDelegate or Info.plist resolves the issue.
According to UIWindow documentation;
If the window has an existing view hierarchy, the old views are
removed before the new ones are installed.
Source Link -> here
So, system automatically destroy while decide to no longer need your first RootViewController. You can handle transition like this;
if var topRootController = UIApplication.sharedApplication().keyWindow?.rootViewController {
while (topRootController.presentedViewController != nil) {
topRootController = topRootController.presentedViewController!
}
topRootController.presentViewController(homeController, animated: true, completion: nil)
}
After upgrading my project to iOS7
when I do a BACK Button and the UINavigationController goes back to the previous page, an ImageView on the top of the screen shifts down.
I use IB to do my layouts. These are my Simulated Metrics:
I have AutoLayout off. Any ideas on what the issue might be? I wasnt sure if anyone wants to see specific code and I didnt want to clutter up the question with too much code.
Updates: Based on the comment questions, I wanted to make these updates:
In no place in the application .h or .m file do I make any changes to the imageview's sizes or location.
In both the viewDidLoad and viewDidAppear I call a user-defined method called recalculateAll but their is no reference at all to any imageview sizes. Just for trying it out I commented out the entire section and ran the code and it still jumps down.
In my init I do programatically set some imageviews (you see the #132 in what appears to be a bubble) using their x and y's.
Here is a typical navigation I use for moving from the view controller to the tableviewcontroller:
GetTimeOffByType *showTimeOffReport = [[GetTimeOffByType alloc] initWithNibName:#"GetTimeOffByType" bundle:nil];
showTimeOffReport.timeOffType = #"Vacation";
[self.navigationController pushViewController:showTimeOffReport animated:YES];
These are all .xib files, no storyboarding at all. Its basically a view controller which has an embedded UINavigationController with 6 buttons. Each time a button is pressed it pushes a UITableViewController passing different parameters and showing different data. The transition I am using to get back to the original UIViewController is simply the iOS generated BACK button (so no code to show for that)
Update#2 Hopefully this will help someone solve this wierd behavior. So if I were to click on the table view cell on showTimeOffReport to get the cell detail and then using BACK navigate all the way back it doesnt jump down.
Update#3 Ok this is something I just discovered : The issue of jumping down or not is related to the translucency of the UINavigationBar. If you have a Translucent = YES it will start from the top of the window. If you have a translucent = NO it will start from the bottom of the UINavigationBar.
You might try setting the new property on UIViewController edgesForExtendedLayout to UIRectEdgeNone.
Here is a good resource that explains more about how view layouts changed in iOS 7.
See Apple Documentation
If you plan to be backwards compatible you will probably need to do some runtime checks and adjust positioning if the device is not running iOS 7.
This might help you..You can try adding UIViewControllerBasedStatusBarAppearance key and set it's value NO in your info.plist
UIViewControllerBasedStatusBarAppearance = NO
Happy Memorial Day for those in America!
I am new to iOS and Objective-C programming; a few weeks ago I inherited an iPad app-in-development that was being designed for iOS 5. I now have everything working except the rotation in iOS 6. I know that iPad apps should rotate to every orientation be default (which is what I want), yet mine does not. Everything rotates perfectly in iOS 5, and I can get my splash screen to rotate perfectly in iOS 6, but that is all. I cannot get the activities (once you click through the splash screen) to rotate properly.
I have searched stackoverflow and other websites to figure out what I must do, so I know to implement -(BOOL)shouldAutorotate and -(NSUInteger)supportedInterfaceOrientations in any specific ViewController to control that view's orientation behavior. I've read that having that different rotation behavior in one VC can affect the entire app. So I made sure that every VC that I could find** would now implement those two iOS 6 methods to return YES and UIInterfaceOrientationMaskAll, respectively. That didn't work. I read about returning self.tabBarController.shouldAutorotate and self.tabBarController.supportedInterfaceOrientations in those methods to ensure that the tabbar rotation behavior is consistent, but that didn't work. I have read about implementing a category (UITabBarController+autoRotate.m and .h) that implements these two methods, and that didn't work. I have read about subclassing the tabBarController, and I think my code does that: in my appDelegate, I call
[myWindow setRootViewController:activityViewController],
where activityViewController is an instance of class BicycleFamilyAcitivityViewController, which is from
#interface BicycleFamilyActivityViewController : UIViewController <UITabBarControllerDelegate>
When I investigate what is being called during the successful splash screen rotation using the iOS 6 simulator, I notice that those two implemented methods in BicycleFamilyAcitivityViewController are being called (twice each, actually) and that -(void)willAnimateRotationToInterfaceOrientation:duration is as well. When I try to rotate while viewing an activity (after clicking through the splash screen), those two methods are only called once, and -(void)willAnimateRotationToInterfaceOrientation:duration is not called. In both instances, the appDelegate's -(NSUInteger)application:supportedInterfaceOrientationsForWindow method is called.
Any advice on how to get rotation to work throughout the entire app? Even if it's just pointing to an answer on StackOverflow that I haven't yet seen (or fully understood), I would be most grateful.
Many thanks in advance!
Bernie
** In looking for VC classes in the project, I made sure to consider any class that implemented the rotation method of iOS 5: -(BOOL)shouldAutorotateToInterfaceOrientation:interfaceOrientation
In iOS 6 the Orientation functions have changed. Your set up should look like this in your viewControllers:
-(NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskAll;
}
-(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationLandscapeRight;
}
-(BOOL)shouldAutorotate {
return TRUE;
}
UIInterfaceOrientationMaskAll is all orientations, more information here.
Someone in-house figured out the problem. I thought I would post the answer to help anyone who has a similar predicament.
What I had tried (among other things) was: setting the UIWindow in my appDelegate class to be my instance of a subclass (BicycleFamilyAcitivityViewController) of UIViewController. In my appDelegate, I had:
[myWindow setRootViewController:activityViewController];
where activityViewController is an instance of a subclass of UIViewController.
But I should have created an additional UIWindow via delegate, then assign the TabBarController (tbc) as it's root VC when I build my TabBarController. In my primary view controller class, I had a buildTabBarController function. So these two lines in that function allowed my rotation to work:
UIWindow *keyWindow = [[[UIApplication sharedApplication] delegate] window];
[keyWindow setRootViewController:tbc];
Hope this helps!
Background: I want to make sure my viewControllers rotate properly when it appears. My viewControllers have excellent codes managing the rotation and orientation when it is visible.
Problem: Given two viewControllers in a NavigationController, viewC1 and viewC2. I did the following:
1.) Set rootViewController to viewC1
2.) Push viewC2 into the NavigationController
3.) Rotate
4.) Pop viewC2
5.) viewC1 is still stucked in the old orientation look (as in the transformation code in willAnimateRotationToInterfaceOrientation was not called) with the new orientation.
What can I do to ensure viewC1 call willAnimateRotationToInterfaceOrientation to reconstruct itself to look correctly in the new rotation?
Additional info:
This is all code (no storyboard/xib). I have shouldAutorotateToInterfaceOrientation return YES on all the views. I use willAnimateRotationToInterfaceOrientation to manage all my rotation.
Oh, and please no hacks. For example, copy the code from rotation then check the rotation mannually and manage it in viewDidAppear.
Think about the name of the method, and what you're trying to achieve.
willAnimateRotationToInterfaceOrientation indicates that the view controlled by the view controller is about to animate to a particular orientation. If your view is in the middle of a navigation stack, then it is not being displayed on screen. To animate something that isn't on screen is costly and ultimately worthless. So, that particular method is out of the question, but the problem that remains is there isn't anything else more appropriate in UIKit. The reason is to rotate something (even if not animated) when it's offscreen is worthless cost. It's the responsibility of the developer to handle a change in orientation when the view appears ("transformation on demand" as you will).
You say you don't want hacks, but the method you've described as a hack is probably the most appropriate thing to do. Having a generic method named something like
-(void) updateLayoutForOrientation:(UIInterfaceOrientation)orientation animated:(BOOL)animated { ... }
isn't a bad idea. This can be the handler for orientation change transformations for the whole view controller.
The places you need to possibly check/handle orientation issues are
-(void) viewWillAppear:(BOOL)animated
-(void) willAnimateRotationToInterfaceOrientation: (UIInterfaceOrientation) interfaceOrientation duration: (NSTimeInterval) duration
and in both of these, call updateLayoutForOrientation:animated: to do the work for you.
Short version:
I'm alloc/init/retaining a new UIViewController in one UIViewControllers viewDidLoad method, adding the new View to self.view. This usually works, but it seems to mess up orientation change handling of my iPad app.
Longer version:
I'm building a fairly complex iPad application, involving a lot of views and viewcontrollers. After running into some difficulties adjusting to the device orientation, I made a simple XCode project to figure out what the problem is.
Firstly, I have read the Apple Docs on this subject (a small document called "Why won't my UIViewController rotate with the device?"), and while I do believe it has something to do with one of the reasons listed there, I'm not really sure how to fix it.
In my test project I have an appDelegate, a rootViewController, and a UISplitViewController with two custom viewControllers. I use a button on the rootViewController to switch to the splitViewController, and from there I can use a button to switch back to the rootViewController. So far everything is great, i.e. all views adjust to the device orientation.
However, in the right viewController of the splitViewController, I use the viewDidLoad method to initialize some other viewControllers, and add their views to its own view:
self.newViewController = [[UIViewController new] autorelease];
[newViewController.view setBackgroundColor:[UIColor yellowColor]];
[self.view addSubview:newViewController.view];
This is where things go wrong. Somehow, after adding this view, adjusting to device orientation is messy. On startup everything is fine, after I switch to the splitViewController everything is still fine, but as soon as I switch back to the rootViewController it's all over. I have tried (almost) everything regarding retaining and releasing the viewcontroller, but nothing seems to fix it.
As you can see from the code above, I have declared the newViewController as a property, but the same happens if I don't.
Shouldn't I be adding a ViewController's view to my own view at all? That would really mess up my project, as I have a lot of viewControllers doing all sorts of things.
Any help on this would be greatly appreciated...
I had the same problem, seams resolved by removing from the parent view the "autoresize subview" option in IB.
Select the view a then: Inspector -> Attributes (first tab) -> drawing.
What I think is happening is that your new viewcontroller is getting the autorotation calls and probably not handling them. Meanwhile your old viewcontrollers and its views won't get the autorotation calls and will be stuck in whatever orientation they were in.
I can't tell, but I think what you want to do is to make a UIView and add it to your old viewcontroller, instead of making a UIVIewController and adding its view.