UINavigationController containment, iOS7 and Status Bar. Bug? - ios

I'm updating my custom "iAD Banner Controller" to support iOS 7.
It's basically an UIViewController container composed of 3 views:
the main view (the view of the contained controller)
the banner view
a status bar background view
When the AD is available, there is an animated transition that makes the banner view and the status bar background view appear sliding from the top.
This is all managed using autolayout, and should appear like this (the status bar background is the green one, and in this case it contains an UINavigationController):
The problem is this: Using UINavigationController as the contained controller, when the banner is not visible, the nav controller extends 20px under the status bar. This is ok and expected.
But, when I move it's superview (the container) down to let the iAD banner appear, the 20px extension remains there, with this result:
However, if I do something like rotating the interface, the nav controller detects that the status bar is "far", and then adjusts itself.
I tried to call setNeedsStatusBarAppearanceUpdate and layoutIfNeeded respectively on the controller and it's view, without results.
I attach the whole project if you want to have a look: Link to the project

By now I solved using a workaround: when the AD appear / disappear I call
[self.navigationController setNavigationBarHidden:YES animated:NO];
[self.navigationController setNavigationBarHidden:NO animated:NO];
using this workaround, I force UINavigationController to detect again that the status bar is "far" and It has to recalculate the offset.
Since my view hierarchy is not so simple, and I want to re-use my AD Controller in other projects, I used a Notification to alert that the AD was appearing/disappearing.
I'll wait for other better answer a few day before marking this as correct.
Thanks

Related

NavigationBar not appearing in second view controller

i am working on iPhone app.. i am using navigation controller, but the when i am going to the second view controller i.e. to the child view controller, the navigation bar is not appearing i had tried all the solutions around. Changing the property from translucent to inferred, vice-versa, tried doing it in code in viewDidLoad, viewDidAppear, viewWillAppear, everything..
Need some help..
In simulator it is showing and working perfectly but in device it isn't. I am using iphone 4s.
Check screenshot at below location:
http://postimg.org/image/y3nzz6t79/
I wanted to use below existing Back functionality - hence the transitions:
http://postimg.org/image/r2q34a4sr/
Try to embed your second view controller with Navigation Controller.
Set Top bar property to Opaque
Add this code in ViewDidAppear
[[self navigationController] setNavigationBarHidden:NO animated:YES];

How to push entire view in iOS including navigation bar and toolbar

I have 3 views connected together via a navigation controller. The middle view (#2) has special styling in that the navigation bar and toolbar are completely white to blend in with the white background.
When swiping to/from view 2 the navigation and toolbar transition is animated (as is the default) to slowly fade in the buttons and styling of the view being pushed/popped i.e. the navigation bar and toolbar remain visible during the transition.
This ends up not looking to great because of the white navigation bar and toolbar of view 2.
What I would like to achieve instead is to have each view pushed/popped in entirety i.e. including its navigation bar and toolbar. In other words, instead of the navigation bar and toolbar to persist during the transition, I would like them to slide in/out with the view they are part of.
I have attached screenshots of the 2 variants.
Would it be best to scrap the navigation controller and set up each view with its own navigation bar and toolbar? Or can this be achieved easily for my current setup.
It would be great if someone could point me in the right direction.
This is from the Apple Remote app showing the effect I would like to create.
This is from the Apple Mail app showing the default transition effect.
Use custom transitions between view controllers will give you a better effect than animating UIView's, though you can add physics behaviors to UIView objects to make it more interesting.
Apple uses interactive custom transitions (just look that up) for its own apps. Here is a good article about that too:
http://www.doubleencore.com/2013/09/ios-7-custom-transitions/
Create your view with the desired screen with navigation bar & tollbar.
On the action bring the view 2 or remove with the animation your want using view animation.
[UIView animateWithDuration:0.2
animations:^{set your fram(0,0,320,480/568) or (320,0,320,480/568)}
completion:^(BOOL finished){
}];
You can add the view to keywindow.
Hope this will help you.
Why don't you simply use the hidesBottomBarWhenPushed property over the destination view controller?
// hide the bottom tabbar when we push this view controller
destinationViewController.hidesBottomBarWhenPushed = YES;

Transitioning between transparent navigation bar to translucent

In Apple's recently released Remote app I noticed the way in which the navigation bar behaves is unique and I haven't been able reproduce it. When popping the Now Playing view controller the navigation bar remains transparent for the Now Playing view controller and the navigation bar for the library view controller also stays translucent (Screenshot 1). I'm trying to figure out if they are using two navigation controllers or only one. Personally I feel they're using just one for two reasons (1) the interactive pop gesture is enabled; (2) when you press the 'Now Playing' button in the library view controller, just before the now playing screen has finished 'push view controller' animation the navigation bar becomes transparent (Screenshot 2). This is the behaviour I experience when pushing my view controller (which sets the navigation bar to transparent). So my question is: How does Apple present both navigation bars of the two view controllers as if they were individual (as with Screenshot 1), even the bar buttons, navigation title etc... are 100% in opacity when switching (usually when pushing/popping the buttons and titles of the previous view controller fade as the new controller is being pushed). I've tried playing around with the bar tint colour in viewDidAppear and viewWillAppear in both view controllers but cannot reproduce the same behaviour, and cannot prevent the bar buttons from fading.
Gosh I hope I've explained this well, I get confused just thinking about it!
Screenshot 1 (Popping):
Screenshot 2 (Pushing):
I just downloaded the application to make sure. Two different navigation bars are used. You can see this by using the interactive pop gesture. Notice how the navigation bar on the bottom view controller slides in and out. During normal push and pop transitions, the navigation items just fade in and out on the existing bar, while the bar is stationary. This is what happens up until the point where the now playing view controller is pushed.
If you look quickly, during the now playing view controller animation, you can see the bottom navigation bar disappear.
From my experience with UIKit behavior and what I see in the app, here is what I think happens:
album_vc = the bottom, list view controller
nowplaying_vc = the top view controller
On nowplaying_vc's viewWillAppear:
Set the navigation bar to hidden using [self.navigationController setNavigationBarHidden:YES animated:YES];. Since this is in animation block, this will make the navigation bar slide out during the push animation.
Set [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent; Pretty sure about this, because notice there is no animation in the transition of the status bar styles. It just becomes white.
On nowplaying_vc's viewWillDisappear:
Set the navigation bar to shown using [self.navigationController setNavigationBarHidden:NO animated:YES];. Since this is in animation block, this will make the navigation bar slide in during the pop animation.
Set [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleDefault; Again, notice how during interactive pop gesture, the status bar just changes with no animation.
To achieve the transparent look of the navigation bar of nowplaying_vc, you can use an empty image ([UIImage alloc]) with setBackgroundImage:forBarPosition:barMetrics:.
Since the application does not rotate, we can't be sure if the navigation bar on nowplaying_vc is part of another navigation controller or just a navigation bar on the top with a position of UIBarPositionTopAttached. For all we know, there isn't even a navigation bar there but just a back chevron image view (back bar button is comprised of an image view and a button).
I think the status bar style is changed in viewWillAppear: and viewWillDisappear: due to the unnatural feel there is during interactive pop gesture. I would recommend using an animated transition, or even better, use the new view controller-based status bar style, which the system animates transitions by itself.
Update for modern API:
You should use the animateAlongsideTransition:completion: or animateAlongsideTransitionInView:animation:completion: API, rather than relying on the implicit animations of viewWillAppear: and viewWillDisappear:.
Instead of hiding and showing the navigation bar, you can update the alpha for the navigation bar. It will animate smoothly during the transition. For the view controller with transparent nav bar, instead of modifying the nav bar, create a navbar (or just the back button and title etc.) manually in the second controller's view. We will then hide the navbar when transitioning from first view controller to the second one.
On your first controller's viewWillDisappear and on your second view controller's viewWillAppear:, set the navigation bar alpha to zero using self.navigationController.navigationBar.alpha = 0;. Since this is in animation block, this will make the navigation bar disappear during the push animation.
Set the alpha back to one in first controller's viewWillAppear and second controller viewWillDisappear.

iOS Push Navigation Controller, without a bar on the second view

I have an iOS App, designed within a UINavigationController. One of the pushed view controllers, however, needs a full screen view, without the navigation bar on the top. (to get back, there is just a small, circular button). However, any method I've tried of 'hiding' the navigation bar (navigationCtl.navigationBar.hidden=TRUE) leaves me with ugly artifacts - calling that before the view is pushed (in viewDidLoad or viewWillAppear) causes the previous view controllers bar to flash white just as the slide left animation starts. Similarly, calling it in viewDidAppear leaves a white bar at the top of the second view, along with several subviews pushed down, out of the way. Is there any way I can just have the new view slide over as it usually does, but when it comes over, there's simply no navigation bar up top?
Please note, to help Google, essentially the question here is:
How to animate between two UIViewControllers, when one has a navigation bar at the top, and the other one does not have a navigation bar at the top. So, how to navigate from a UIViewController with a navbar to one without a navbar - avoiding the horrible flickering.
The amazing answer is given below by Ev ... awesome.
give this a spin and see how it works for you.
in the destination view controller in viewWillAppear
- (void)viewWillAppear:(BOOL)animated {
[self.navigationController setNavigationBarHidden:YES animated:YES];
}
It actually has a cool effect and can be useful. in the viewWillAppear everything happens before the view is displayed so it takes away the strange artifacts.
be well

Hidden UINavigationController inside UITabBarController

I have an application with 5 UIViewControllers each inside a corresponding UINavigationController, all tucked inside a UITabBarController that displays 5 tabs at the bottom of the screen.
I want to display another UIViewController (inside a UINavigationController) when a dialog button is pressed.
This view should only be loaded and unloaded programatically; i.e. it should not appear in the tab bar. However, I want the tab bar to be visible always.
If I add the [UINavigationController view] to [self window] the UITabBar is covered. If I add it to any other layer, the UINavigationController adds on the compensation it has for the status bar so appears further down than expected.
A solution would be to have the 6th UINavigationController added to the UITabBar with the others, but with its tabBarItem hidden. Then I can show it and hide it using the tabBars selectedIndex property.
Accessing the tabBarItem through the UIViewController shows no obvious way of doing this.
#wisequark, I think you completely misunderstood and you have almost rewritten the architecture of my application. However I have a separate navigation controller for each view as they are mutually exclusive and there is no concept of "drilling down".
#Kendall, This is what I expect I will have to do - have the modal view appear with a hide button to bring back the normal interface. But it would be nice to keep the tab bar always visible, so I was just wondering if anyone knew of a way.
It sounds as though you have a mess on your hands. A UINavigationController is a distinct object that is very different from a UITabBarController. In general, your application should have a tab controller, one of who's tab's loads a UINavigationController which in turn loads it's views - not that both maintain management over the different views. It is also improper to refer to the display of a UIViewController as such an object doesn't have a visual representation. In the case of a UINavigationController, the navigation controller object is responsible for displaying a navigation bar and a table view (in the most common case) and for managing the display of all the views in the navigation hierarchy. It itself has no corresponding representation on screen. Similarly, a UITabBarController presents a tab bar and is responsible for the loading and unloading of the views and/or view controllers attached to the tab buttons. If we were to present this as an image, it would look something like this -
alt text http://img.skitch.com/20081112-2sqp7q4wafa34te1ga337u4k8.png
Well, it sounds like what you really want to do is present a modal view with the tab bar still visible. You could add your view as a subview of the tab bar controller's view. The tab bar's view is, oddly enough, not the tab bar itself but rather a view containing the tab bar and the selected item's view.
Alternatively, you could try calling presentModalViewController:animated: with the selected tab (i.e. [tabBarController.selectedViewController presentModalViewController:animated:]) as the receiver instead of the tab bar. I seem to recall doing this once (quite by accident) and the tab bar remained visible.
One more thought: since each of your five view controllers is a UINavigationController, you could always pushViewController:animated: onto the selected view controller, then hide the back button. Your view will just appear without animation. But you'll need to remember to pop your view controller off the stack whenever the user switches to another tab. That might take a bit more work.
The best idea I could think of would be to either push a modal navigation controller for your view (which would hide the tab bar which you do not want), or to get the tab bar controller current selected view controller (really your navigation controller for a tab) and push your new view controller on there - and then pop that view when another tab is selected with a tab bar delegate.
It seems wierd to me to push the view onto random tabs though, if the view is created from a dialog that is modal, I don't see why the view itself should not also be modal and hide tabs.

Resources