I have a view controller navigation hierarchy where only the top view controller hides has its navigation bar hidden. Normal pushing/popping is fine and works as expected. However, when the pop is interactive (drag-to-pop), the top opaque bar doesn't disappear until the transition is finished. I've implemented the logic in the following delegate call:
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
if( [viewController isKindOfClass:[MyTopViewController class]] == YES ) {
id<UIViewControllerTransitionCoordinator> transitionCoordinator = viewController.transitionCoordinator;
if( transitionCoordinator != nil && transitionCoordinator.initiallyInteractive == YES ) {
[transitionCoordinator notifyWhenInteractionEndsUsingBlock:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
if( context.isCancelled == YES ) {
return;
}
[navigationController setNavigationBarHidden:YES animated:animated];
}];
} else {
[navigationController setNavigationBarHidden:YES animated:animated];
}
} else {
[navigationController setNavigationBarHidden:NO animated:animated];
}
}
I've already attempted numerous variations of this, but each one has had various issues with interactive transitions, especially if the transition is canceled mid-way. What's the best way to approach this?
Related
I have a UIViewController vc1 which is pushed after UIViewController vc2.
Both vc1 and vc2 are with transparent background.
Problem:
When I try to pop vc2 with interactive pop gesture (pan from edge), in my view stack appears mysterious UIParallaxDimmingView which darkens my stack (under transparent view controllers there is a background image).
As soon as I release finger, cancel or finish transition it becomes clear/transparent again.
How can i disable/remove UIParallaxDimmingView or set it transparent?
If it is pushing a VC(still animating) when you try to pop VC with interactive pop gesture(pan from edge), the app may be frozen. This can help you :
/ set gesture no when pushViewController /
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
if ([self respondsToSelector:#selector(interactivePopGestureRecognizer)]) {
self.interactivePopGestureRecognizer.enabled = NO;
}
[super pushViewController:viewController animated:animated];
}
/ set gesture yes when showViewController /
- (void)navigationController:(UINavigationController )navigationController didShowViewController:(UIViewController )viewController animated:(BOOL)animated
{
if ([navigationController respondsToSelector:#selector(interactivePopGestureRecognizer)]) {
navigationController.interactivePopGestureRecognizer.enabled = YES;
}
/ if rootViewController, set delegate nil /
if (navigationController.viewControllers.count == 1) {
navigationController.interactivePopGestureRecognizer.enabled = NO;
navigationController.interactivePopGestureRecognizer.delegate = nil;
}
}
I have view controller say A i am going from A to B.Then on B by pressing back button i am coming to A.Now i want to know from which view controller i am coming back.Please tell me how can i do this.I know i can do it by using viewWillAppear method but don't want to use this.
Please tell which is the best way of doing it?
-(void)viewWillAppear:(BOOL)animated
{
NSLog(#"view will appear called");
}
You have been push to B-VC from A-VC right.You can come back by popping.
self.navigationController!.popViewControllerAnimated(true)--Write this code in B-VC
VC-ViewController.
- (id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC
{
NSLog(#"from VC class %#", [fromVC class]);
if ([fromVC isKindOfClass:[ControllerYouJustPopped class]])
{
NSLog(#"Returning from popped controller");
}
return nil;
}
This really saved me .
you can pass id of controller before pop A.h #property NSInteger childVC; A.m
-(void)viewWillAppear:(BOOL)animated
{
if (_childVC == 3){
//todo
}
}
B.m
-(void) viewWillDisappear:(BOOL)animated {
A *parent = (A *)self.navigationController.viewControllers[self.navigationController.viewControllers.count - 2];
parent.childVC = 3;
[super viewWillDisappear:animated];
}
I do not see other ways
You could use a navigation controller delegate and implement the following UINavigationControllerDelegate method:
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
UIViewController *fromViewController = [navigationController.transitionCoordinator viewControllerForKey:UITransitionContextFromViewControllerKey];
NSLog(#"%#", fromViewController.title);
}
I am using Navigation controller.
In my first screen their is no need of NavigationBar. As this is the Home screen.So I am hiding it using this code:
- (void)viewWillAppear:(BOOL)animated
{
[self.navigationController setNavigationBarHidden:YES];
}
When I push to new screen I am showing the NavigationBar using this code:
- (void)viewWillAppear:(BOOL)animated
{
[self.navigationController NO];
}
The problem is when I come back from other screens to my HomeScreen I am getting black screen in place of navigationBar.
Here is the problem in Image:
White color screen is my ViewController which has navigation bar and BLue one has'n Navigation bar. How can I remove the black part.
Click on the navigation controller and go to attribute inspector and uncheck the show navigation bar option as shown in the screenshot:
try this one
self.navigationItem.hidesBackButton = YES;
There is a better way to do it. All you need to do is create a subclass of UINavigationController class. Set the UINavigationControllerDelegate. Add the following method in the class.
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
if([viewController isKindOfClass: [SomeClass class]])
[self setNavigationBarHidden: NO];
else
[self setNavigationBarHidden: YES];
}
OR
-(void)viewWillDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
[self.navigationController setNavigationBarHidden:NO animated:YES];
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES animated:YES];
}
This is related to another question of mine, iOS 8 + interactive transition + nav bar shown = broken?, but is different.
On iOS 8, when one is doing an interactive transition from view A to view B via the NavigationControllerDelegate / UIViewControllerInteractiveTransitioning method, and view A has a navbar, and view B does NOT, then what is the correct method to hide / unhide the nav bar?
I tried to do this in the ViewController like this:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[self transitionCoordinator] animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
if (self.navigationController) {
[self.navigationController setNavigationBarHidden:YES animated:animated];
}
} completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
NSArray *debugViews = [context containerView].subviews;
NSLog(#"%#", debugViews);
if ([context isCancelled] ) {
if( self.navigationController ) {
[self.navigationController setNavigationBarHidden:NO animated:animated];
}
}
}];
}
- (void)viewWillDisappear:(BOOL)animated {
[[self transitionCoordinator] animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
if (self.navigationController) {
[self.navigationController setNavigationBarHidden:NO animated:animated];
}
} completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
if ([context isCancelled] ) {
if( self.navigationController ) {
[self.navigationController setNavigationBarHidden:YES animated:animated];
}
}
}];
[super viewWillDisappear:animated];
}
... but there are two big problems:
The view (mainly the navbar) "flickers" sometimes when animation is completing. This is really ugly if you have a complex view underneath.
If the user cancels the interactive transition (ie. by not dragging far enough or pinching enough) then the navbar goes away forever, even though I can see in the code that it's being told to unhide.
Here is some soure-code to show this happening: https://github.com/xaphod/UIViewControllerTransitionTut
--> un-pinch to go from one view controller to another; the first view has a nav bar, the second one does not. When you complete the transition, you can sometimes see flickering (problem 1 above). When you un-pinch just a little bit and let go, that's a cancelled transition: although you're still on view 1, the navbar has disappeared (problem 2 above).
The right way to hide the navigation bar will be to use Navigation's controller delegate,make sure you set the window's navigation controller delegate to self before using the following delegate method:-
Just do this in the AppDelegate.m
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window.rootViewController.navigationController.delegate=self;
//do your rest code...
}
-(void)navigationController:(UINavigationController *)navController
willShowViewController:(UIViewController *)viewController
animated:(BOOL)animated
{
[navController setNavigationBarHidden:([viewController isKindOfClass:[CustomViewController class]])
animated:animated]; // just mention the view controller class type for which you want to hide
}
Referred from this SFO's
If you wants to hide navigation bar in particular viewcontroller you can use this method in wilAppear.
//Unhide
-(void)viewWillAppear:(BOOL)animated
{
self.navigationController.navigationBarHidden = NO;
}
//Hide
-(void)viewWillAppear:(BOOL)animated
{
self.navigationController.navigationBarHidden = YES;
}
I have a tabbar with splitviewcontroller on every item. I used a subclass from that site https://github.com/grgcombs/IntelligentSplitViewController and in iOS 4 every worked fine, but in iOS 5 I have a problem. When I start the app in portrait mode, then change to landscape and go to the second item in tabbar, then again change to portrait mode and click the popover, then dismiss the popover, go to the first item in tabbar, again open popover and change to the landscape, the master view disappears and popover is still visible. Has anyone any idea how to fix it?
I have been working on solving the same problem. Instead of using the UISplitViewController subclass you indicate, I created a UITabBarController subclass which properly propagates the rotation messages to all UISplitViewControllers it contains. This maintains the correct internal state of the UISplitViewControllers. However, one of the SplitViewController delegate methods is not called if the SplitViewController is not visible, so I handle this in the detail view controller. I've confirmed this works in iOS5.0 - iOS6.1
OSTabBarController.m
#import "OSTabBarController.h"
#implementation OSTabBarController
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
for(UIViewController *targetController in self.viewControllers){
if(targetController != self.selectedViewController && [targetController isKindOfClass:[UISplitViewController class]]){
[targetController willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
}
}
}
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{
[super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
for(UIViewController *targetController in self.viewControllers){
if(targetController != self.selectedViewController && [targetController isKindOfClass:[UISplitViewController class]]){
[targetController didRotateFromInterfaceOrientation:fromInterfaceOrientation];
}
}
}
#end
DetailViewController
#implementation OSDetailViewController
-(void)viewWillAppear:(BOOL)animated{
//the splitViewController:willHideViewController:withBarButtonItem:forPopoverController: may not have been called
if(!UIInterfaceOrientationIsPortrait(self.interfaceOrientation)){
self.navigationItem.leftBarButtonItem = nil;
}
}
#pragma mark - UISplitViewControllerDelegate Methods
- (void)splitViewController:(UISplitViewController *)splitController willHideViewController:(UIViewController *)viewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)popoverController
{
[self.navigationItem setLeftBarButtonItem:barButtonItem animated:YES];
}
- (void)splitViewController:(UISplitViewController *)splitController willShowViewController:(UIViewController *)viewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem
{
[self.navigationItem setLeftBarButtonItem:nil animated:YES];
}
#end