Device Orientation in iOS 6.0 UINavigationController - objective-c

I have a UINavigationController in UITabbarcontroller. I want to rotate only one view cotnroller inside UINavigationController.
Here is the code snippet I am using.
-(NSUInteger)supportedInterfaceOrientations
{
if (CURRENTDEVICE == IPHONE)
return [self.navigationController supportedInterfaceOrientations] | UIInterfaceOrientationMaskAllButUpsideDown;
else
return UIInterfaceOrientationMaskAll;
}
-(BOOL)shouldAutorotate {
return YES;
}
I have a category on UINavigationController as well:
#import "UINavigationController+autorotate.h"
#implementation UINavigationController (autorotate)
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAllButUpsideDown;
}
#end
I am not sure how to implement it.

you can hard code it with cgrect. here is a link to another question that might help you. there is a nice example of hard coding two different views for rotation in there, but i don't recomend it personally. anyhow i thought that might point you to the right direction.
https://stackoverflow.com/questions/12867792/ios-rotation-causing-views-to-displace-shift-forcing-me-to-use-non-sensical-har
there is a set of codes in that question that might get you started. you also have an option in starboard( if you are using storyboard) to set rotations in IB which is much easier.
hope this helps
adrian

In your category in the supportedInterfaceOrientations implementation, you could check for the topViewController. You can use kindOfClass: method to work out which class it is... Then return a different orientation from the default of your navigation.
You could also subclass UINavigationController, and do this check the same way. Subclassing the navigation controller isn't recommended until, iOS 6, the documentation still states this but Apple engineers have told me that with the new rotation logic, you can subclass the UINavigationController.

Related

Application tried to present modally an active controller : UIImagePickerController

I'm struggle at this for 2 days and believe that this is the moment I should call for help. After I search SOF for a while, none of any answer could solve my problem. Here are my application ...
In the application,
Device is iPad, iOS 6
RootViewController is NavigationController
TopViewController is TabBarController
In this TabBarController, I present a popoverController from right bar button of navigation bar
In presenting popover there is a button to allow user to pick image from by taking new one or pick from existing.
To pick new one, I presentViewController UIImagePickerController to allow user to take photo with divice camera. presentModalViewController:animated: if iOS < 6, and presentViewController:animated:completion: for iOS > 6
I also hide Status Bar before presentation
To select from existing photo, I do presentPopoverFromBarButtonItem:permitArrowDirections:animated:
PopoverViewController also referencing by A TabBarController
Here is the issue
Present UIImagePickerController will always failed if user try to pick new one first with exception "Application tried to present modally an active controller <[name of view controller that try to present]>"
BUT, if user try to pick image from camera roll for once and then try to take new one again, it won't fail.
Here are what I tried
present from RootViewController
present from TopViewController (TabBarController)
present from popoverViewController itself
present from a tab of TabBarController
hide popoverViewController before presentation
resignFirstResponder from a textField in popoverViewController
Here is the current code I'm using
// PopoverViewController, presented by a tab in TabBarController
- (IBAction)takePhoto:(id)sender {
[self.delegate takePhotoWithDeviceCamera];
}
// A Tab in TabBarController, delegate of popoverViewController
- (void)takePhotoWithCamera {
[[UIApplication sharedApplication] setStatusBarHidden:YES];
if ([UIDevice OSVersion] < 6.0) {
[self presentModalViewController:cameraPicker animated:YES];
} else {
[self presentViewController:cameraPicker animated:YES completion:nil];
}
}
Any idea what would cause this error? Any suggestion are welcome. Thank you.
Got the same trouble than you and finally got the solution based on #CainaSouza's answer. I've been working with Xamarin.iOS so I'll make my answer in C#, but it can be easily translated to Objective-C.
I'm using the same code as #CainaSouza to call the controller:
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController (customController, true, null);
And then I add the following code to my custom RootViewController:
public override void PresentViewController (UIViewController viewControllerToPresent, bool animated, Action completionHandler)
{
if (PresentedViewController != viewControllerToPresent) {
base.PresentViewController (viewControllerToPresent, animated, completionHandler);
}
}
The trick is to check if you haven't presented that UIViewController before.
I know it's an old question, but hope it will help someone. :)
Present the imagePicker controller in a popoverController(in case of iPad). This will not give you that error.
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:picker];
[popover presentPopoverFromRect:self.selectedImageView.bounds inView:self.selectedImageView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
self.popOver = popover;
}
else {
[self presentModalViewController:picker animated:YES];
}
Best Regards.
Have you tried to present it like this?
[self.view.window.rootViewController presentModalViewController:cameraPicker animated:YES];
My guess is that the cameraPicker instance is not correctly allocated/released. Try creating the cameraPicker inside your - (void)takePhotoWithCamera method rather than relying on a previously created instance. You'll get a handle to the picker instance in the callback methods...
I had the same problem - I wanted users to take photos using a full screen view (i.e. call presentViewController and pass UIImagePickerController controller instance) and select existing photos from a popover (I associated it with a popover using initWithContentViewController). I reused the same instance of UIImagePickerController for both camera and popover and it threw the same exception if I tried to run a camera before opening a popover.
I turned out to cause a problem and my solution was simply to have two instances of UIImagePickerController - one for camera (which I presented from a main view) and another one for popover. It works so far. :-)
Not sure if it is still actual for the original poster, but hopefully it will help anyone else who encounter this discussion.

Hiding NavigationBar before and after segue

I have an application where a TableView Controller segues to a ViewController and then to another.
I want to maximize real estate in the TVC and use
[self.navigationController setNavigationBarHidden: YES animated:YES];
to hide the bar. However, the bar returns to the view on the return from segue.
The app was constructed in storyboard for 5.1 using Xcode 4.3.1.
Can anyone assist by telling me where I can place a similar instruction to remove the Navbar on return from segue OR suggest an alternative method.
I have exhausted all means in storyboard by changing attributes for the controllers involved. However what you see in Storyboard isn't always what I get.
I found the answer above in the comment so just documenting it because I used it and it worked well! Thanks to #Tomasz.
To prevent the navigation bar reappearing in the header once you go back with the segue, use the following:
-(void)viewWillAppear:(BOOL)animated
{
[self.navigationController setNavigationBarHidden: YES animated:YES];
}
Swift solution
override func viewWillAppear(animated: Bool) {
self.navigationController?.setNavigationBarHidden(true, animated: true)
}
Thanks #spacemonkey and #Tomasz, this worked.

Topbar cannot rotate in landscape view with storyboard

I have just converted from .nib files to storyboard, but suddenly the view wont rotate topbar in landscape view. All the settings are "inferred" in my view, and i have not really made any changes since the conversion.
Is this a common problem when upgrading? I have not found any specific info.
And furthermore i do not force any view rotations in my code.
If any more info is needed i can supply anything!
Thanks in advance.
ViewController:
- (void) viewDidLoad {
[super viewDidLoad];
self.view.autoresizingMask = UIViewAutoresizingNone;
self.view.autoresizesSubviews = UIViewAutoresizingNone;
}
I've taken a look at your code and you seem to be missing a method that allows your view controller to rotate freely.
Subclass UIViewController e.g. like this:
// .h file
#interface OrientationAwareViewController : UIViewController
#end
// m.file
#implementation OrientationAwareViewController
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return YES;
}
#end
Then set OrientationAwareViewController in the storyboard as your main view controller's class name. That said, I have no idea how this worked for you when using nibs :) Documentation says clearly:
By default, this method returns YES for the UIInterfaceOrientationPortrait orientation only. If your view controller supports additional orientations, override this method and return YES for all orientations it supports.

Cocoa-Touch internals: How does the view know its controller?

If you add a subview to a view or add a view to a window, how does iOS know which controller this view belongs too?
Easy example:
Have a UIView without UIViewController and add it to the window [window addSubView:myView] --> it will not rotate.
Now use a UIViewController, have it implement shouldAutoRotateToInterfaceOrientation: and add the controller's view to the window: [window addSubView:myController.view] --> magically, the view will adjust to interface orientation.
But look at the code: in both cases a UIView was added. How can iOS possibly be aware that in the second case a UIViewController was involved?
I'm interested in how this is done internally. My best guess is that UIViewController.view is a setter which adds the controller to an internal array of controllers or assigns itself to some internal variable which holds the currently active controller.
Simple. Look in UIView.h. It's right there. Each UIView has a pointer back to a UIViewController (which is apparently referred to as the "viewDelegate").
Dave DeLong is correct (and gets +1) as it is clearly defined UIView.h as #package so anything in UIKit can access it.
Here is an example of accessing that variable for educational purposes only (obviously you will not do this in a real application).
SomeAppDelegate.m
#synthesize navigationController=_navigationController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
// Add the navigation controller's view to the window and display.
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
//DO NOT TRY THIS AT HOME
UIView *mynavview = self.navigationController.view;
//Guaranteed _viewDelegate atleast in iOS 4.3
Ivar ivar = class_getInstanceVariable([UIView class], "_viewDelegate");
UIViewController *controller = object_getIvar(mynavview, ivar);
NSLog(#"controller = self.navigationController? %#", controller == self.navigationController ? #"Yes" : #"No");
return YES;
}
UIViewController has a private class method (called controllerForView:, I believe) which is used to find the view's controller. Internally, there is probably a table used to connect the two together, and this method simply finds the proper location in that table and returns its value. When the result is nil, the default implementation will be used (don't rotate).
If you want to be sure about the name of the method, set a breakpoint in -[UIView becomeFirstResponder], tap on a text field, and step through the code until it shows up in the call stack. I suggest using becomeFirstResponder because it is easier to control than most things which get the view controller.

Two UIViews in one .xib file?

i made a second uiview in mei .xib file. the first view is landscape and i get it by following code
ItemController *newItem;
newItem = [[ItemController alloc] init];
newItem.view.....
how can i "activate" the second view, so i can use it with
newItem.view2...
is that possible? the second view is portait mode, so it should be hidden and when turning the ipad the first view should be hidden and the second gets visible.
thanks
If I understand your question correctly, you can use the method willRotateToInterfaceOrientation:duration: in UIViewController.
You can declare two UIView variables and set connections to them using IB:
IBOutlet UIView *view1;
IBOutlet UIView *view2;
Then, in willRotateToInterfaceOrientation:duration: you can swap the views. Assuming that your ItemController is a subclass of UIViewController, you could have something like this:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) || (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight) {
[self setView:view1];
}
else {
[self setView:view2];
}
}
When the user rotates the iPad this method will get called automatically.
NOTE: make sure you set shouldAutorotateToInterfaceOrientation: to return YES, and you may have to check the orientation to set the view property to the correct view initially.
EDIT: My answer is assuming that you have two views with distinct layouts/elements and not two views that are essentially the same thing sized for different orientations. If the latter is the case, there is probably a better way to do it using only one view.
The approach you are taking will lead you to a trouble situation when you have some IBActions to associate with click of buttons or change the label text (which is on xib) etc.
The best approach is to change the frame height width and positions when the orientation changes. Although this is difficult in beginning but it will save you from lots of troubles.
For assistance check Rotate UIViewController to counteract changes in UIInterfaceOrientation
Hope this helps.
Thanks,
Madhup