44

In my app I have multiple view controllers, and most have a right-hand-side UIBarButtonItem with direct "show" segue actions attached.

Having segued to another view and then pressed the '< Back' button, the original button item remains faded out, although still otherwise usable.

This only appears to happen under iOS 11.2.

I can't see any setting that could be doing this, and in at least one of the cases where this happens there's no specific segue unwinding nor viewDidAppear handling. I'd post some code, but AFAICS it's all just default UINavigationBar behaviour.

Alnitak
  • 334,560
  • 70
  • 407
  • 495

4 Answers4

37

This is a bug in iOS 11.2 and happens because the UIBarButtonItem stays highlighted after navigation and does not return to its normal state after the other view controller pops.

To avoid this behavior, either

  1. use a UIBarButtonItem with a UIButton as a custom view

  2. disable and re-enable the bar button item in viewWillDisappear(_:) (although this causes the button to appear immediately, use matt's solution to avoid this):

    barButtonItem.isEnabled = false
    barButtonItem.isEnabled = true
    
Tamás Sengel
  • 55,884
  • 29
  • 169
  • 223
  • Thanks for the reply. Might it also be possible to reset the button's state in the `viewDidAppear()` method? – Alnitak Dec 11 '17 at 14:09
  • @Alnitak I added a second option to my answer which addresses the issue in a different way. – Tamás Sengel Dec 11 '17 at 14:11
  • 1
    thanks - either seems to work, I'm unsure which I find more visually appealing. If I do it in `viewWillDisappear(_:)` then the button is immediately visible when the view pops. If I do it in `viewDidAppear(_:)` then it animates back into visibility. – Alnitak Dec 11 '17 at 14:14
  • 1
    p.s. if you know of any links to other reports of this behaviour that would be very useful – Alnitak Dec 11 '17 at 14:23
  • 1
    You can also flip the enabled state in `viewDidDisappear` instead of `viewWillDisappear`. No visual artifacts. – jab Apr 09 '18 at 15:09
  • Strange. Neither solution working on my side when doing pop navigation with custom interactive animator :0 – Vlad Jun 13 '18 at 12:21
  • I ended up with UIBarButtonItem with custom view (UIButton) inside. – Vlad Jun 13 '18 at 13:04
24

What I do is work around this bug, in the view controller's viewWillAppear, as follows:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    self.navigationController?.navigationBar.tintAdjustmentMode = .normal
    self.navigationController?.navigationBar.tintAdjustmentMode = .automatic
}

That seems to wake up the button without visual artifacts.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • It's not working when user swiped back using edge gesture. Tried viewDidAppear and it works but then when we go back using button it has a small delay for view to appear. Any thoughts how we can improve this? – mkz Jan 02 '18 at 15:06
  • Thanks! This works for me. Both for clicking the back button and swiping. – derf26 Jan 08 '18 at 20:22
5

Another work around is to implement the fix on the parent navigationController - so that each of its child viewController's gets the fix as follows

NOTE: This requires the receiving class to be setup as the UINavigationController delegate

Swift

func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
    if #available(iOS 11.2, *) {
        navigationBar.tintAdjustmentMode = .normal
        navigationBar.tintAdjustmentMode = .automatic
    }
}

Objective-C

-(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {    
    if (@available(iOS 11.2, *)) {
        self.navigationBar.tintAdjustmentMode = UIViewTintAdjustmentModeNormal;
        self.navigationBar.tintAdjustmentMode = UIViewTintAdjustmentModeAutomatic;
    }
}
microbee
  • 61
  • 3
  • Not sure if I'm doing something wrong, but I cannot get this (or any other workaround) to work when I'm using `popViewController(_)` to go back to the view in question. Is anyone experiencing the same thing? – Linus Unnebäck Mar 21 '18 at 18:47
2

I solved it like this:

override func viewWillDisappear(_ animated: Bool) {
    navigationController?.navigationBar.tintAdjustmentMode = .normal
    navigationController?.navigationBar.tintAdjustmentMode = .automatic
}

so it will restore the color before the other view appear

Alex Balan
  • 61
  • 7