This seems to be a bug that was introduced in iOS 7.1. In my case it is caused by a UIToolbar placed directly below the navigation bar. The dark shadow also appears in the translucent tab bar.
The shadow seems to be caused by the background view of the UIToolbar. I now use this workaround in the view controller with the toolbar that hides the toolbar's background view during the transition:
Here is my variation...it requires much less code than tom's answer, and is more efficient. This is IF you want a translucent navigation bar, and also want to fix that shadow problem.
In the source ViewController (that is embedded in the Navigation Controller)...
It seems to happen with any bar (TabBar or ToolBar) that is translucent.
So one way to fix it is to set the _tabBar.translucent = NO; (in my case). This prevents the undesired shadow under the top navigation bar while leaving the navigation bar translucent. Unfortunately the bottom bar is no longer translucent though.
It can be set back to translucent but all this has to happen after the whole pushing animation is finished thus switching this property is well noticeable.
In case, however the bottom bar also has to be translucent and I don't want the user to see the change I resolved it with the following:
/* create a simple quick animation of the bottom bar
just before pushing the new controller */
[UIView animateWithDuration:0.1
animations:^{
_tabBar.barTintColor = [UIColor colorWithWhite:0.97254901960784 alpha:1.0]; // this is the closest color for my case
_tabBar.translucent = NO;
} completion:^(BOOL finished) {
/* now when the animation that makes the bar not translucent
is finished we can push the new controller
the controller is instantiated before the animation code */
[self.navigationController pushViewController:controller animated:YES];
}];
Then in the viewDidAppear: I simply reverts that back:
There is just a little change in the appearance especially but it's barely noticeable and it's way better than having the shadow under the navigation bar.
Hope it'll help others to keep bars translucent until Apple fix this behaviour as bars ARE meant to be hidden in some cases unlike it was suggested in other posts especially for the UITabBar
Or if you're using interface builder, you can just select Navigation Bar from your navigation controller and uncheck the Translucent checkbox between Style and Bar Tint in the Attributes Inspector to get rid of that weird effect -
nonamelive's answer is perfect. To achieve the same thing in Interface Builder AND STILL KEEP TRANSLUCENCY, select the navigation controller and set a user defined runtime attribute view.backgroundColor as shown in the screenshot (in the Identity Inspector). Repeat for all navigation controllers that show this problem.
It seems that this whole problem occurs because the black color (or actually, no color) of UINavigationController is leaking through at the time CoreGraphics snapshots it at animation begin. So, setting it to white will prevent that.
For those, who have implemented tabBar and want to have both nav and tab bar still translucent, I found an easy workaround after dealing with painful "tabBar snapshot while push" workaround for a two years.
The trick is to:
set clear backgroundView on the tab bar, that cause to layout the view controllers differently
set a new BlurEffect view below first button
constraint the blur view to tabBar (UIView)
Before I was using a snapshot of the tabBar and was setting alpha of the tabBar to 0, but that cause unwanted safeLayoutGuide offsets. As this solution does now access any private variables, I hope this is green to go to AppStore (I'm not yet there).
In viewDidLoad of my UITabBarController I set following:
//Setting background image to empty image to prevent a bug under top right navigation bar corner
tabBar.backgroundImage = UIImage()
//As that turns of the blur effect I am adding a new view imitating the same
let blurView = UIVisualEffectView()
blurView.effect = UIBlurEffect(style: .systemChromeMaterial)
blurView.frame = tabBar.bounds
blurView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
blurView.isUserInteractionEnabled = false
tabBar.insertSubview(blurView, belowSubview: tabBar.subviews.first!)