I have now been stuck on this problem for more then 2 weeks! In my project, I have 1 single ViewController(slide) I want to enable both landscape and portrait in. The rest of all controllers/views(slides) I want to enable portrait-mode only.
The tricky part is, the "ViewController" I am referring to is connected to both NavigationControllers and TabBarControllers. See the scheme below where the ViewController I want to enable both landscape/portrait is named: ReferredViewController.
TabBarController ----> NavigationController ----> FristViewController --(push event)--> ReferredViewController
So far I have tried to make a CATEGORY for both NavigationControllers and TabBarControllers. But since my NavigationControllers and TabBarControllers are placed at the very start of the project this will set the rules for the whole project. My ReferredViewController is placed at the end or in the middle of the projects "storyboard". I have tried to set the rules by code aswell for the single ReferredViewController without any success.
My best shot is to change the event between FirstViewController and ReferredViewController from "push" to "modal". ReferredViewController can then rotate both portrait/landscape and the rest of the project is locked in portrait. BUT, as you may know all navigations (NavigationBar) will be lost and the user will become stuck at that single slide.
So I am trying to enable the NavigationBar with the following code example in the ReferredViewController.m file:
ShowTaskViewController *detailViewController = [[ShowTaskViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:detailViewController];
navController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self.navigationController presentModalViewController:navController animated:YES completion:nil];
[navController release];
[detailViewController release];
But ofc nothing happens and I am back to square one again :O. FML!
In this line:
[self.navigationController presentModalViewController:navController
animated:YES
completion:nil];
you are conflating two UIViewController instance methods:
- (void)presentViewController:(UIViewController *)viewControllerToPresent
animated:(BOOL)flag
completion:(void (^)(void))completion
- (void)presentModalViewController:(UIViewController *)modalViewController
animated:(BOOL)animated
The first of these is now the standard, the second method was deprecated in ios6.
Also the presenting view controller should be self (the ReferredViewController), not self's navigationController.
Your presented view controller can dismiss itself thus
[[self presentingViewController] dismissViewControllerAnimated:YES
completion:(void (^)(void))completion];
But take a look at fibnochi's answer, it may be a better way for you to achieve your result.
you have to over ride UITaBarController because it is you base view controller. I have done this for my navigation controller. Tell me if this helped.
#interface UINavigationController (Autorotation)
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation;
- (BOOL) shouldAutorotate;
- (NSUInteger) supportedInterfaceOrientations;
#end
#implementation UINavigationController (Autorotation)
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
if ([self.visibleViewController isKindOfClass:[MWPhotoBrowser class]] || [self.visibleViewController isKindOfClass:[ZoomPictureViewController class]]) {
return YES;
}
return (toInterfaceOrientation == UIInterfaceOrientationPortrait);
}
-(BOOL) shouldAutorotate{
return YES;
}
-(NSUInteger) supportedInterfaceOrientations{
if ([self.visibleViewController isKindOfClass:[MWPhotoBrowser class]] || [self.visibleViewController isKindOfClass:[ZoomPictureViewController class]]) {
return UIInterfaceOrientationMaskAll;
}
return UIInterfaceOrientationMaskPortrait;
}
Related
I have a very weird problem with the UINavigationController on iOS 8, maybe someone encountered this already and can shed some light. I have 2 views: let's say view A and view B
I am using it like this:
view A [self.navigationController pushViewController:vc animated:YES];
push to a new view B [self.navigationController pushViewController:vc animated:YES];
push to a new view B [self.navigationController pushViewController:vc animated:YES];
push to a new view B [self.navigationController pushViewController:vc animated:YES];
push to a new view B [self.navigationController pushViewController:vc animated:YES];
push to a new view B [self.navigationController pushViewController:vc animated:YES];
return to view A [self.navigationController popToRootViewControllerAnimated:YES];
The problem is that if I play with this for 2 min and go through this like push-push-push-push-pop and again... at some time it stops animating, for either push and pop.
I checked the 1) view controllers they get deallocated on the pop to root, 2) I don't receive any memory warnings, 3) the navigation controller is the rootviewcontroller of the window so why this problem?
I can't find any explanation maybe someone has encountered this already. Also I am mentioning I am not using custom animations, just the plain native push and pop of a normal UIViewController, not even subclassing that so everything is plain native.
#kokos8998 try using
#interface AnimatorPushGalleryToGallery : NSObject <UIViewControllerAnimatedTransitioning>
and then in view A just add this and will control everything from view B either A->B or B->A (or in case you need something more custom add the same delegate in B as well)
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
self.navigationController.delegate = self;
}
- (nullable id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC
{
if(operation == UINavigationControllerOperationPush)
return [AnimatorPushGalleryToGallery new];
else if(operation == UINavigationControllerOperationPop)
return [AnimatorPopGalleryToGallery new];
return nil;
}
Hello I am quite new to iPhone development (working with iOS 7). Basically I want my application to respond to screen rotations (i.e. changing the screen orientation) My project uses both UITabBarController and UINavigationController. However when I rotate the device it won't call the "shouldAutorotate" function in a ViewController called LoginView.m.
Therefore I have followed the answer in here up to the point where it subclasses both UITabBarController and UINavigationController. Can someone explain to me how to add (i.e reference it)the orientation behaviour within the LoginView.m class or to the entire project.
Your help is greatly appreciated.
Thanks
In your subclassed UItabbarcontroller
- (BOOL)shouldAutorotate {
UINavigationController *navView = (UINavigationController *)[self selectedViewController];
//Get the selected current tab viewcontroller. I guess you are having a Navigationcontroller
UIViewController *vc = [navView.viewControllers objectAtIndex:0];
//Fetch root viewcontroller of your navigationcontroller
return [self checkOrientationForViewController:vc];
}
-(BOOL) checkForViewsForViewController : (UIViewController *)vc{
if([vc isKindOfClass:[FirstViewController class]]){
FirstViewController *vc1 = (FirstViewController *)vc;
return [vc1 shouldAutorotate];
}
if([vc isKindOfClass:[SecondViewController class]]){
SecondViewController *vc2 = (SecondViewController *)vc;
return [vc2 shouldAutorotate];
}
if([vc isKindOfClass:[ThirdViewController class]]){
ThirdViewController *vc3 = (ThirdViewController *)vc;
return [vc3 shouldAutorotate];
}
return YES;
}
In respective viewcontrollers implement the shouldAutorotate method
Instead of using Delegation you can also use
- (NSUInteger)supportedInterfaceOrientations
UINavigationController and UITabBarController ask their child view controllers which interface orientations they support. So you can implement "- (NSUInteger)supportedInterfaceOrientations" in your LoginView.m and return the appropriate interface orientations.
You also need to edit your Info.plist and add the supported interface orientations their. You can do this with Xcode by opening the project view. Also have a look at Apples documentation on supporting interface orientations
Instead of subclassing, is worth to know that there are also delegate methods, in UINavigationcontroller and UITabbarController that make you handle rotations at runtime:
- (UIInterfaceOrientation)navigationControllerPreferredInterfaceOrientationForPresentation:(UINavigationController *)navigationController
Ref doc.
- (NSUInteger)tabBarControllerSupportedInterfaceOrientations:(UITabBarController *)tabBarController
Ref doc.
Evenf if Apple has removed the advice to do not subclass Nav and Tabbar controller, using delegation will be the most reliable solution over time
I know this question has asked by many users,But i did not found any answer related to my issue.
I'm using UISplitViewController ,my application starts with login page, so i have hidden masterView on start, after some time on DetailViewController i shown the master viewController using Delegate method.
- (BOOL)splitViewController:(UISplitViewController *)svc shouldHideViewController:(UIViewController *)vc inOrientation:(UIInterfaceOrientation)orientation NS_AVAILABLE_IOS(5_0)
{
return hideMaster;
}
i have initialised hideMaster to NO ,and my ViewDidLoad() of DetailViewController is below
ViewDidLoad(){
[self.splitViewController.view setNeedsLayout];
self.splitViewController.delegate =Nil;
self.splitViewController.delegate = self;
[self.splitViewController willRotateToInterfaceOrientation:[UIApplication sharedApplication].statusBarOrientation duration:0];
[super viewDidLoad];
}
it worked fine my master is now unhide.But on the same detailViewController i have a Back Button on which i'm poping the current ViewController to last viewController and again i want to hide masterViewController my code for back button is below.
- (IBAction)back:(id)sender {
hideMaster = NO;
self.splitViewController.delegate =Nil;
self.splitViewController.delegate = self;
[self.splitViewController willRotateToInterfaceOrientation:[UIApplication sharedApplication].statusBarOrientation duration:0];
[self.navigationController popViewControllerAnimated:NO];
}
Its poping the CurrentViewController to last ViewController but its not Hiding the masterViewController
Please help me out.
#JohnD,I went through your code.you are hiding the master view controller while poping the last View controller,but the viewController to which you are navigating is still showing the master View controller.therefore your masterView is still there.
follow the steps given below.
1.make delegate of UInavigationController to that ViewController which is your last singleView controller.
2.In last single ViewController(which is delegate of UINavigationController) implement following delegate method.
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
[self.splitViewController.view setNeedsLayout];
self.splitViewController.delegate =Nil;
self.splitViewController.delegate = self;
[self.splitViewController willRotateToInterfaceOrientation:[UIApplication sharedApplication].statusBarOrientation duration:0];
}
3.Now implement delegate method of UISplitViewController in side lastViewController which is given below.
- (BOOL)splitViewController:(UISplitViewController *)svc shouldHideViewController:(UIViewController *)vc inOrientation:(UIInterfaceOrientation)orientation NS_AVAILABLE_IOS(5_0)
{
return hideMaster;<<===============I'm assuming hide master as a variable of shared object(Singleton).
}
4.Now change your - (IBAction)back:(id)sender method with following one.
- (IBAction)back:(id)sender {
hideMaster = Yes;
[self.navigationController popViewControllerAnimated:NO];
}
I hope this will work,if you stuck some where please let me know.
you are using UISplitViewController inside your app,since you have many views but whole app is not using UISplitViewController only one view using it.
Its better to use another approach.
This one is tricky. I have a subclass of UINavigationController that overrides pop/push and present/dismiss methods. Here I customise the behaviour to set the correct size if the UINavigationController subclass is contained in a popover. Nothing too fancy, but I do it this way to don't write subclasses of all my ViewControllers and use Autolayout.
However, the completion blocks of the presentViewController:animated:completion: and dismissViewControllerAnimated:completion: are not being executed. And this is the weird part: the exact same code on iPhone works correctly, but on iPad is not executing the blocks. Here is a code sample.
#interface SBNavigationController : UINavigationController
#end
#implementation SBNavigationController
- (void) presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion
{
if ([viewControllerToPresent isKindOfClass:[UINavigationController class]])
{
UINavigationController *nav = (UINavigationController *) viewControllerToPresent;
[nav.topViewController setContentSizeForViewInPopover:kFullSizePopover];
} else
{
[viewControllerToPresent setContentSizeForViewInPopover:kFullSizePopover];
}
viewControllerToPresent.modalPresentationStyle = UIModalPresentationCurrentContext;
[super presentViewController:viewControllerToPresent animated:flag completion:completion];
}
- (void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion ;
{
[super dismissViewControllerAnimated:flag completion:completion];
}
#end
And the code using it is this:
#implementation SBInviteFBContactViewController
...
- (void) createInviteByMailViewController
{
SBInviteMailViewController *mailInvite = [[SBInviteMailViewController alloc] initWithDelegate:self userInfo:_userInfo];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:mailInvite];
[self.navigationController presentViewController:navController
animated:YES
completion:^{
NSLog(#"presentViewController:");
}];
}
#pragma mark SBInviteMailProtocol
- (void) invitedMailContacts:(NSArray *)contacts;
{
[self.navigationController dismissViewControllerAnimated:YES
completion:^{
NSLog(#"animation Ended");
if (contacts) {
[self.delegate invitedMailContact:contacts];
[self popViewControllerAnimated:YES];
}
}];
}
...
#end
Any ideas?
This seems to be a huge bug. Please report it to Apple (and I am about to do the same). I found my way here because I just discovered the same bug myself, and did a google search to see if anyone else was talking about it.
I've created a very small demonstration project, whose architecture is like this:
ViewController - the main view controller
Its view contains a button Tap Me.
PopoverViewController - presented in popover
When you tap Tap Me in the main ViewController, it creates a UIPopoverController with this vc, PopoverViewController, as its content view controller; its view, too, contains a button Tap Me.
PopoverViewController2 - presented "modally" in same popover
PopoverViewController2 has its modalPresentationStyle set to UIModalPresentationCurrentContext so it can appear inside the popover. When you tap Tap Me in the popover, PopoverViewController calls presentViewController:....
Here's the code:
- (IBAction)doTapMe:(id)sender {
NSLog(#"about to present view controller");
[self presentViewController:[PopoverViewController2 new] animated:YES completion:^{
NSLog(#"in completion handler"); // never called!
}];
NSLog(#"did present view controller");
}
The log reads "about to present view controller" and "did present view controller", but "in completion handler" never appears, even though the "modal" view controller's view appears in the popover just fine.
(Moreover, changing to animated:NO not only doesn't fix it, it causes a visual glitch.)
The UIModalPrsentationCurrentContext style is only available if you are compiling against iOS 3.2 or greater. Can't imagine that is the issue though.
The docs for UIModalPrsentationCurrentContext also say:
When presenting a view controller in a popover, this presentation style is supported only if the transition style is UIModalTransitionStyleCoverVertical. Attempting to use a different transition style triggers an exception. However, you may use other transition styles (except the partial curl transition) if the parent view controller is not in a popover.
This is a strange one.
Any chance you're running a different version of iOS on the iPhone and the iPad?
For my iPad app, I have a view displayed modally as a formsheet when a button is pushed. In order to have the keyboard dismissed after entering text in a textfield i tried as suggested;
the "disablesAutomaticKeyboardDismissal" method.
This does not work, in fact, the method is never called acording to the log.
The keybord will dismiss for iPhone or when i choose to not present modally.
Here is my code:
- (BOOL)disablesAutomaticKeyboardDismissal
{
NSLog(#"method calls");
return NO;
}
- (IBAction)showNewView:(id)sender
{
MyViewController *mvc =
[[MyViewController alloc] init];
// some lines about setting content
//...
UINavigationController *navController = [[UINavigationController alloc]
initWithRootViewController:mvc];
[navController setModalPresentationStyle:UIModalPresentationFormSheet];
[self presentViewController:navController animated:YES completion:nil];
}
-(BOOL)disablesAutomaticKeyboardDismissal
or not, the keyboard is not dismissed unless i remove tis line:
// [navController setModalPresentationStyle:UIModalPresentationFormSheet];
However, then it is not presented the way I want anymore.
Can anyone see what I am doing wrong?
-(BOOL)disablesAutomaticKeyboardDismissal needs to overridden to return NO by the view controller that is presented as a form sheet, not by the presenter; That's your mistake. In your case you could subclass UINavigationController to get the desired behaviour:
#interface AutomaticKeyboardDismissingNavigationController : UINavigationController
#end
#implementation AutomaticKeyboardDismissingNavigationController
- (BOOL)disablesAutomaticKeyboardDismissal
{
return NO;
}
#end
(The class name could probably be a bit shorter and still be comprehensible.)