I have a UINavigationController with a UIViewController (VC1) pushed onto it. VC1 contains a collectionView. When a user taps a cell, a child viewController (VC2) is added to VC1.
VC2 should support all orientations. Whereas VC1 only supports portrait orientation. In portrait mode, I want to be able to present VC2, rotate into landscape, have VC2 adjust its layout accordingly, dismiss VC2, revealing VC1 still in portrait orientation/layout.
The shouldAutorotate method in VC2 gets called when VC2 is presented using the stock method. However this is insufficient because it doesn't allow a custom transition:
(1)
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
CommentsViewController *vc = [[CommentsViewController alloc] initWithNibName:#"CommentsViewController" bundle:nil];
[self presentViewController:vc animated:YES completion:nil];
}
The shouldAutorotate method is NOT called when using presentViewController:animated:completion: with a custom transition or using traditional viewController containment methods. In other words, neither of these work:
(2)
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
CommentsViewController *vc = [[CommentsViewController alloc] initWithNibName:#"CommentsViewController" bundle:nil];
self.transitioningDelegate = [[TransitioningDelegate alloc] init];
vc.modalPresentationStyle = UIModalPresentationCustom;
vc.transitioningDelegate = self.transitioningDelegate;
[self presentViewController:vc animated:YES completion:nil];
}
(3)
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
CommentsViewController *vc = [[CommentsViewController alloc] initWithNibName:#"CommentsViewController" bundle:nil];
[self addChildViewController:vc];
vc.view.frame = self.view.bounds;
[self.view addSubview:vc.view]; // Assume I'm doing a cool custom animation here
[vc didMoveToParentViewController:self];
}
In summary, using approach #1 the rotation methods are called properly. But using #2 and #3 they are not. This prohibits me from building the required custom transition because doing so would mean the child viewController not supporting all orientations.
Any help would be much appreciated.
For background: I am versed in iOS6/7 rotation APIs, UIViewController containment, and custom viewController transitions.
Edit:
I did implement shouldAutomaticallyForwardRotationMethods to no avail.
So, this might not be what you need, but it seems like the presenting view controller maintains control of the shouldAutorotate call if your animated transition does not remove the presenting view controller's view. If you do remove the presenting view controller's view, then the control of the shouldAutorotate call moves up to the presented view controller.
I'm not sure how to send control automatically up without removing the view (so that you can show a transparent view), but you could just forward the shouldAutorotate call manually:
- (BOOL) shouldAutorotate{
if(self.presentedViewController){
return [self.presentedViewController shouldAutorotate];
}
return YES;
}
Not the most ideal though.
Did you happen to implement - (BOOL)shouldAutomaticallyForwardRotationMethods on the parent controller and have it return NO?
You case may be more complex, since you support different rotations for the different parent and child view controllers, but this is a easy gotcha to miss.
Related
I want to recreate the search UI shown in the iOS 7/8 calendar app. Presenting the search UI modally isn't a problem. I use UISearchController and modally present it just like the UICatalog sample code shows which gives me a nice drop down animation. The issue comes when trying to push a view controller from the results view controller. It isn't wrapped in a navigation controller so I can't push onto it. If I do wrap it in a navigation controller then I don't get the default drop down animation when I present the UISearchController. Any ideas?
EDIT:
I got it to push by wrapping my results view controller in a nav controller. However the search bar is still present after pushing the new VC onto the stack.
EDIT (2):
DTS from Apple said that the calendar app uses a non-standard method to push from search results. Instead they recommend removing focus from the search controller then pushing and returning focus on pop. This is similar to the way search in the settings app works I imagine.
Apple has gotten very clever there, but it's not a push, even though it looks like one.
They're using a custom transition (similar to what a navigation controller would do) to slide in a view controller which is embedded in a navigation controller.
You can spot the difference by slowly edge-swiping that detail view back and letting the previous view start to appear. Notice how the top navigation slides off to the right along with the details, instead of its bar buttons and title transitioning in-place?
Update:
The problem that you're seeing is that the search controller is presented above your navigation controller. As you discovered, even if you push a view controller onto a navigation controller's stack, the navigation bar is still beneath the search controller's presentation, so the search bar obscures any (pushed view controller's) navigation bar.
If you want to show results on top of the search controller without dismissing it, you'll need to present your own modal navigation view controller.
Unfortunately, there's no transition style which will let you present your navigation controller the same way the built-in push animation behaves.
As I can see, there are three effects that need to be duplicated.
The underlying content dims, as the presented view appears.
The presented view has a shadow.
The underlying content's navigation completely animates off-screen, but its content partially animates.
I've reproduced the general effect within an interactive custom modal transition. It generally mimic's Calendar's animation, but there are some differences (not shown), such as the keyboard (re)appearing too soon.
The modal controller that's presented is a navigation controller. I wired up a back button and edge swipe gesture to (interactively) dismiss it.
Here are the steps that are involved:
In your Storyboard, you would change the Segue type from Show Detail to Present Modally.
You can leave Presentation and Transition set to Default, as they'll need to be overridden in code.
In Xcode, add a new NavigationControllerDelegate file to your project.
NavigationControllerDelegate.h:
#interface NavigationControllerDelegate : NSObject <UINavigationControllerDelegate>
NavigationControllerDelegate.m:
#interface NavigationControllerDelegate () <UIViewControllerTransitioningDelegate>
#property (nonatomic, weak) IBOutlet UINavigationController *navigationController;
#property (nonatomic, strong) UIPercentDrivenInteractiveTransition* interactionController;
#end
- (void)awakeFromNib
{
UIScreenEdgePanGestureRecognizer *panGestureRecognizer = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)];
panGestureRecognizer.edges = UIRectEdgeLeft;
[self.navigationController.view addGestureRecognizer:panGestureRecognizer];
}
#pragma mark - Actions
- (void)handlePan:(UIScreenEdgePanGestureRecognizer *)gestureRecognizer
{
UIView *view = self.navigationController.view;
if (gestureRecognizer.state == UIGestureRecognizerStateBegan)
{
if (!self.interactionController)
{
self.interactionController = [UIPercentDrivenInteractiveTransition new];
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
}
}
else if (gestureRecognizer.state == UIGestureRecognizerStateChanged)
{
CGFloat percent = [gestureRecognizer translationInView:view].x / CGRectGetWidth(view.bounds);
[self.interactionController updateInteractiveTransition:percent];
}
else if (gestureRecognizer.state == UIGestureRecognizerStateEnded)
{
CGFloat percent = [gestureRecognizer translationInView:view].x / CGRectGetWidth(view.bounds);
if (percent > 0.5 || [gestureRecognizer velocityInView:view].x > 50)
{
[self.interactionController finishInteractiveTransition];
}
else
{
[self.interactionController cancelInteractiveTransition];
}
self.interactionController = nil;
}
}
#pragma mark - <UIViewControllerAnimatedTransitioning>
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)__unused presented presentingController:(UIViewController *)__unused presenting sourceController:(UIViewController *)__unused source
{
TransitionAnimator *animator = [TransitionAnimator new];
animator.appearing = YES;
return animator;
}
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)__unused dismissed
{
TransitionAnimator *animator = [TransitionAnimator new];
return animator;
}
- (id<UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id<UIViewControllerAnimatedTransitioning>)__unused animator
{
return nil;
}
- (id<UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id<UIViewControllerAnimatedTransitioning>)__unused animator
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu-conditional-omitted-operand"
return self.interactionController ?: nil;
#pragma clang diagnostic pop
}
The delegate will provide the controller with its animator, interaction controller, and manage the screen edge pan gesture to dismiss the modal presentation.
In Storyboard, drag an Object (yellow cube) from the object library to the modal navigation controller. Set its class to ourNavigationControllerDelegate, and wire up its delegate and navigationController outlets to the storyboard's modal navigation controller.
In prepareForSegue from your search results controller, you'll need to set the modal navigation controller's transitioning delegate and modal presentation style.
navigationController.transitioningDelegate = (id<UIViewControllerTransitioningDelegate>)navigationController.delegate;
navigationController.modalPresentationStyle = UIModalPresentationCustom;
The custom animation that the modal presentation performs is handled by transition animator.
In Xcode, add a new TransitionAnimator file to your project.
TransitionAnimator.h:
#interface TransitionAnimator : NSObject <UIViewControllerAnimatedTransitioning>
#property (nonatomic, assign, getter = isAppearing) BOOL appearing;
TransitionAnimator.m:
#implementation TransitionAnimator
#synthesize appearing = _appearing;
#pragma mark - <UIViewControllerAnimatedTransitioning>
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
return 0.3;
}
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
// Custom animation code goes here
}
The animation code is too long to provide within an answer, but it's available in a sample project which I've shared on GitHub.
Having said this, the code, as it stands, was more of a fun exercise. Apple has had years to refine and support all their transitions. If you adopt this custom animation, you may find cases (such as the visible keyboard) where the animation doesn't do what Apple's does. You'll have to decide whether you want to invest the time to improve the code to properly handle those cases.
I know this thread is old, but there seems to be a much simpler approach to getting the desired behavior.
The important thing to realize is the UISearchController is presented from the source controller, which is a view controller inside the navigation controller. If you inspect the view hierarchy, you see that the search controller, unlike regular modal presentations, isn't presented as a direct child of the window, but rather as a subview of the navigation controller.
So the general structure is
UINavigationController
MyRootViewController
UISearchViewController (presented pseudo-"modally")
MyContentController
Essentially you just need to get from the MyContentController up to the MyRootViewController, so you can access its navigationController property. In my tableView:didSelectRowAtIndexPath: method of my search content controller, I simply use the following to access my root view controller.
UINavigationController *navigationController = nil;
if ([self.parentViewController isKindOfClass:[UISearchController class]]) {
navigationController = self.parentViewController.presentingViewController.navigationController;
}
From there you can easily push something onto the navigation controller, and the animation is exactly what you'd expect.
EDIT: an alternate solution that doesn't rely on a UIWindow. I think the effect is very similar to the calendar app.
#interface SearchResultsController () <UINavigationControllerDelegate>
#end
#implementation SearchResultsController
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// this will be the UINavigationController that provides the push animation.
// its rootViewController is a placeholder that exists so we can actually push and pop
UIViewController* rootVC = [UIViewController new]; // this is the placeholder
rootVC.view.backgroundColor = [UIColor clearColor];
UINavigationController* nc = [[UINavigationController alloc] initWithRootViewController: rootVC];
nc.modalPresentationStyle = UIModalPresentationCustom;
nc.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[UIView transitionWithView: self.view.window
duration: 0.25
options: UIViewAnimationOptionTransitionCrossDissolve | UIViewAnimationOptionAllowAnimatedContent
animations: ^{
[self.parentViewController presentViewController: nc animated: NO completion: ^{
UIViewController* resultDetailViewController = [UIViewController alloc];
resultDetailViewController.title = #"Result Detail";
resultDetailViewController.view.backgroundColor = [UIColor whiteColor];
[nc pushViewController: resultDetailViewController animated: YES];
}];
}
completion:^(BOOL finished) {
nc.delegate = self;
}];
}
- (void) navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
// pop to root? then dismiss our window.
if ( navigationController.viewControllers[0] == viewController )
{
[UIView transitionWithView: self.view.window
duration: [CATransaction animationDuration]
options: UIViewAnimationOptionTransitionCrossDissolve | UIViewAnimationOptionAllowAnimatedContent
animations: ^{
[self.parentViewController dismissViewControllerAnimated: YES completion: nil];
}
completion: nil];
}
}
#end
ORIGINAL solution:
Here's my solution. I start out using the same technique you discovered in the UICatalog example for showing the search controller:
- (IBAction)search:(id)sender
{
SearchResultsController* searchResultsController = [self.storyboard instantiateViewControllerWithIdentifier: #"SearchResultsViewController"];
self.searchController = [[UISearchController alloc] initWithSearchResultsController:searchResultsController];
self.searchController.hidesNavigationBarDuringPresentation = NO;
[self presentViewController:self.searchController animated:YES completion: nil];
}
In my example, SearchResultsController is a UITableViewController-derived class. When a search result is tapped it creates a new UIWindow with a root UINavigationController and pushes the result-detail view controller to that. It monitors for the UINavigationController popping to root so it can dismiss the special UIWindow.
Now, the UIWindow isn't strictly required. I used it because it helps keep the SearchViewController visible during the push/pop transition. Instead, you could just present the UINavigationController from the UISearchController (and dismiss it from the navigationController:didShowViewController: delegate method). But modally-presented view controllers present on an opaque view by default, hiding what's underneath. You could address this by writing a custom transition that would be applied as the UINavigationController's transitioningDelegate.
#interface SearchResultsController () <UINavigationControllerDelegate>
#end
#implementation SearchResultsController
{
UIWindow* _overlayWindow;
}
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// this will be the UINavigationController that provides the push animation.
// its rootViewController is a placeholder that exists so we can actually push and pop
UINavigationController* nc = [[UINavigationController alloc] initWithRootViewController: [UIViewController new]];
// the overlay window
_overlayWindow = [[UIWindow alloc] initWithFrame: self.view.window.frame];
_overlayWindow.rootViewController = nc;
_overlayWindow.windowLevel = self.view.window.windowLevel+1; // appear over us
_overlayWindow.backgroundColor = [UIColor clearColor];
[_overlayWindow makeKeyAndVisible];
// get this into the next run loop cycle:
dispatch_async(dispatch_get_main_queue(), ^{
UIViewController* resultDetailViewController = [UIViewController alloc];
resultDetailViewController.title = #"Result Detail";
resultDetailViewController.view.backgroundColor = [UIColor whiteColor];
[nc pushViewController: resultDetailViewController animated: YES];
// start looking for popping-to-root:
nc.delegate = self;
});
}
- (void) navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
// pop to root? then dismiss our window.
if ( navigationController.viewControllers[0] == viewController )
{
[_overlayWindow resignKeyWindow];
_overlayWindow = nil;
}
}
#end
As you present a viewController the navigationController becomes unavailable. So you have to dismiss your modal first and then push another viewController.
UISearchController must be rootViewController of a UINavigationController and then you present navigation controller as modal.
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 am trying to figure out for a while now, how should I use the annotation button to switch
to another mapView. The app I am working on uses MapBox - maps. I checked the exemples
provided by them, but programmatically switching between two maps is there always achieved
through tab bar (which is not the case I want to use).
I am working with storyboards and I understood it quit well, how the segue should be made
in the Interface builder, but I think I am not managing with the programmatically integrated
buttons on map views. I initiated 'id's in both header files and I proclaimed them in the
Identity Inspector as well.
This is the part of the code, where I implement the RMMMapView with the annotation in the
main View Controller - ViewController and it works perfectly:
- (void)viewDidLoad{
[super viewDidLoad];
RMMapBoxSource *onlineSource = [[RMMapBoxSource alloc] initWithMapID:(([[UIScreen mainScreen] scale] > 1.0) ? kRetinaMapID : kNormalMapID)];
_mapView = [[RMMapView alloc] initWithFrame:self.view.bounds andTilesource:onlineSource];
_mapView.tileSource = [[RMMapBoxSource alloc] initWithMapID:(([[UIScreen mainScreen] scale] > 1.0) ? kRetinaMapID : kNormalMapID)];
_mapView.centerCoordinate = CLLocationCoordinate2DMake(0,0);
_mapView.adjustTilesForRetinaDisplay = YES;
_mapView.zoom = 4;
_mapView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self.view addSubview:_mapView];
_mapView.showsUserLocation = YES;
[_mapView setConstraintsSouthWest:[_mapView.tileSource latitudeLongitudeBoundingBox].southWest
northEast:[_mapView.tileSource latitudeLongitudeBoundingBox].northEast];
RMPointAnnotation *annotation = [[RMPointAnnotation alloc] initWithMapView:_mapView
coordinate:_mapView.centerCoordinate andTitle:#"Hello, world!"];
[_mapView addAnnotation:annotation];
}
and this is the part, where I try to call the LowContentMap viewController, from the ViewController - main ViewController:
- (void) prepareForSegue:(UIStoryboardSegue *) segue sender:(id) sender {
if ([segue.identifier isEqualToString:#"Hello, world!"]) {
//LowContentMap *lowContentMap = segue.destinationViewController;
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:[NSBundle mainBundle]];
LowContentMap *lowContentMap = [storyboard instantiateViewControllerWithIdentifier:#"lowContentMap"];
lowContentMap.lcm = _vc;
}}
This is the part of the code, that should be filled in:
- (void)mapView:(RMMapView *)mapView annotationView:(RMPointAnnotation *)annotation calloutAccessoryControlTapped:(UIControl *)control{
[self performSegueWithIdentifier:#"ShowSomeViewController" sender:annotation];
}
It would be really great, if somebody would try to resolve the problem.
I followed the discusion between Noa and Kronos at:
Setting up a detail view controller using a segue
but I still think, the part with the 'id' is something I am doing wrong. Thanks in advance.
1. I think your problem is that you don't know how to display another viewController
You should give the "View Controller Programming Guide" a good read, especially the part "Presenting View Controllers from Other View Controllers"
http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/Introduction/Introduction.html
I also recommend to check out some of the awesome WWDC videos that show how to use ViewControllers.
2. How to create and display a viewController
There are many ways to do it. E.g. using the storyboard to create and display the viewController, define a protocol in the child controller, override "performSegueWithIdentifier" to set the delegate and implement the protocol to dismiss the vc.
However, in your case, it seems to make sense to do it all programmatically. Thus, you need to:
a) find the right place to add your action
b) alloc and init your view controller:
MyController *myController = [[MyController alloc] init];
// setup as required, there should be at least a delegate (being able to dismiss the view)
myController.delegate = self;
If you have designed your viewController in a storyboard, you might want to use this alloc/init routine instead:
MyController *myController = [[UIStoryboard storyboardWithName:#"Main.storyboard" bundle:nil] instantiateViewControllerWithIdentifier:#"MyController"];
myController.delegate = self;
c) display your new view controller;
this depends on if you have a navigationController:
[self.navigationController pushViewController:myController animated:YES];
...or if you want to present it modally:
[self presentViewController:myController animated:YES completion:NULL];
d) dismiss when done;
when your other controller is done with whatever it does, it should inform its delegate (implement your own protocol!) that it's done and should be dismissed. The delegate is the original viewController that created (alloc'd/inited) the "myController":
// this method should be defined in a protocol and implemented in the vc that created (and owns) the child view controller
// typically, this is the parent view controller
- (void)done {
[self dismissViewControllerAnimated:YES completion:NULL];
}
if you used a navigationController it's not -dismissViewControllerAnimated:, but
[self.navigationController popViewControllerAnimated:YES];
hope this helps to clarify things
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;
}
I have one view controller, named AViewController. There is a button in AViewController. When the button is clicked, i will present another view controller,lets called BViewController. If AViewController is in portrait-orientation, it works well.If the orientation is in landscape, then the BViewController is still initialized in portrait but presented in landscape.
This is the problem. I wonder how can i init BViewController in current orientation. I use [UIScreen mainScreen].bounds in the BViewController's init. but the bounds is not in landscape if the device is in landscape. I know pass the frame from AViewController to BViewController, it may work. but i don't think this is a good solution. So is there any better ways?
the function to present BViewController is as follows:
- (void)BtnClicked
{
BViewController *bvc = [[BViewController alloc] init];
bvc.delegate = self;
bvc.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:movie animated:YES completion:nil];
}
I still don't know how to do it efficiently. But i use one solution to call the willAnimateRotationToInterfaceOrientation method manually in viewDidAppear.
the snippet is as follows:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self willAnimateRotationToInterfaceOrientation:[UIApplication sharedApplication].statusBarOrientation duration:0];
}