How to properly refresh a UINavigationBar?

11,253

Solution 1

After trying various methods to refresh, I find this is the least ugly solution that seems to work (back then on iOS 10 but apparently not currently on iOS 13, i.e., don't count on this):

guard let navigation = navigationController,
      !(navigation.topViewController === self) else {
    return
}
let bar = navigation.navigationBar
bar.setNeedsLayout()
bar.layoutIfNeeded()
bar.setNeedsDisplay()

Other methods tried:

  • Presenting a view controller (causes screen to flicker in some cases)
  • Hiding and re-showing the bar (breaks bar if half-way between backswipe to previous VC)
  • Setting the bar's layer's frame (does not seem to work reliably, and is explicitly forbidden by the documentation for navigationBar)

Solution 2

This works for me

_ = navigationController.view.snapshotView(afterScreenUpdates: true)

Solution 3

UIButton *leftbtn  = [UIButton buttonWithType:UIButtonTypeCustom] ;

[leftbtn addTarget:self action:@selector(city:) forControlEvents:UIControlEventTouchUpInside];
[leftbtn setImage:[UIImage imageNamed:@"location"] forState:UIControlStateNormal];
leftbtn.contentHorizontalAlignment   = UIControlContentHorizontalAlignmentLeft;
[leftbtn sizeToFit];
self.citybtn = leftbtn;
UIBarButtonItem* cityBtn =  [[UIBarButtonItem alloc] initWithCustomView:leftbtn];

UIBarButtonItem *left_fixedSpaceBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
left_fixedSpaceBarButtonItem.width = -17;
self.navigationItem.leftBarButtonItems = @[left_fixedSpaceBarButtonItem,cityBtn];

.........

when u change

[self.citybtn setTitle:city forState:UIControlStateNormal];

[self.citybtn sizeToFit];

Share:
11,253
MJQZ1347
Author by

MJQZ1347

Updated on June 18, 2022

Comments

  • MJQZ1347
    MJQZ1347 almost 2 years

    In relation to this question: How to change Back button text from within the child view controller? I am searching for a propery way to refresh the navigation bar after changing the back button title with previousViewController.navigationItem.backBarButtonItem?.title = "New Title".

    The (not so ideal?) solution from the linked question:

    if let navigationController = self.navigationController {
        navigationController.popViewControllerAnimated(false)
        navigationController.pushViewController(self, animated: false)
    }
    

    Edit:

    Apparently changing the layer frame forces the navigation bar to refresh. Not a solution, but a less expensive(?) workaround I guess:

    if let navigationController = self.navigationController {
        navigationController.navigationBar.layer.frame.insetInPlace(dx: 0.1, dy: 0)
        navigationController.navigationBar.layer.frame.insetInPlace(dx: -0.1, dy: 0)
    }
    
  • MJQZ1347
    MJQZ1347 over 7 years
    But what about the back arrow? It is missing?
  • tech4242
    tech4242 over 7 years
    @MJQZ1347 Just add "<" to the title and play around with the font? Or check this out: stackoverflow.com/a/18874211/6597361 But either way it's a very easy way out of your situation
  • MJQZ1347
    MJQZ1347 over 7 years
    Unfortunately swipe to go back doesn't work anymore with that workaround. Also there must be an easier way to refresh the navigation bar without popping the VC?
  • tech4242
    tech4242 over 7 years
    @MJQZ1347 I just browsed through stackoverflow myself and I couldn't find another way for refreshing except what you had already mentioned and I also tried a few things a few minutes ago; regarding my answer - swiping left could be restored easily though but if you are extensively using IB for your layout then it's not very neat; but as I said from the beginning a complete refresh is not supposed to happen - only changing tintColor etc.
  • MJQZ1347
    MJQZ1347 over 7 years
    Yeah, probably. Please see my updated question, there are maybe better workarounds to make the navigation bar refresh.
  • tech4242
    tech4242 over 7 years
    @MJQZ1347 It might be better than the initial popping of the VC. If it were up to me though, I would change the UIBarButtonItem as it looks less like a hack and I am pretty sure it will hold better in the long haul if combined with the left swipe in a clean function. You have the shorter solution but just logically speaking you do want a "new" button as semantically the button will do something "different"
  • Arkku
    Arkku over 4 years
    @airowe It was also a weird hack found by trial and error. Unfortunately I don't know of a better way. If this doesn't work, I would maybe try presenting (and immediately dismissing) a transparent (or very small) view controller.
  • airowe
    airowe over 4 years
    No doubt. Just wanted to let future people know in case they stumbled on it. No downvote or anything. Crazy this still hasn't been figured out.
  • Lew Winczynski
    Lew Winczynski about 3 years
    Your answer is not clear and in wrong format. Please, read how to answer and edit accordingly.