8

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)
}
Community
  • 1
  • 1
MJQZ1347
  • 2,607
  • 7
  • 27
  • 49
  • A lot of times, when there's not a straight-forward way to do what you want to do, it's for good reason. The back-button should take the user back to where they came from and their navigation history shouldn't be rewritten. If you need some other sort of behavior (other than navigating back) in that top left corner, you don't need to be using the `backBarButtonItem`. – nhgrif Aug 21 '16 at 16:05
  • In some particular situations changing the title improves the user experience. Take WhatsApp as an example. – MJQZ1347 Aug 21 '16 at 16:08
  • Assume I've never used WhatsApp. – nhgrif Aug 21 '16 at 16:09
  • @MJQZ1347 So I checked out WhatsApp on my iPhone just in case I had missed something - I am positive that they are just creating the UIBarButtonItem every time they switch to another VC; I couldn't see a "refresh" i.e. changing the title of the button from within the same VC there – tech4242 Aug 21 '16 at 19:15
  • 1
    When you are in a chat and somebody texts you in another chat the back button title changes from "Chats" to "Chats(x)" where x stands for the number of opem chats. – MJQZ1347 Aug 21 '16 at 19:17

4 Answers4

14

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)
Arkku
  • 41,011
  • 10
  • 62
  • 84
  • 1
    @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. – Arkku Jan 29 '20 at 19:22
  • 1
    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. – airowe Jan 29 '20 at 19:24
1

This works for me

_ = navigationController.view.snapshotView(afterScreenUpdates: true)
Jonesy
  • 195
  • 8
1
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];

ttayaa
  • 11
  • 1
  • Your answer is not clear and in wrong format. Please, read [how to answer](https://stackoverflow.com/help/how-to-answer) and edit accordingly. – Lew Winczynski Apr 10 '21 at 09:53
-2

One solution would be to have a function, which changes the UIBarButtonItem completely by removing/hiding the back button and showing a custom UIBarButtonItem in its place with the navigationItem.leftBarButtonItem property. Surely not ideal but the button is not meant to be changed mid-VC lifecycle so I guess you could try. In that sense there is no "proper" way as this is not considered standard behaviour.

It worked for me when I added this function to a button on a sample View Controller:

func changeBackButton() {
    navigationItem.hidesBackButton = true
    navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Test", style: .plain, target: self, action: #selector(test))
}
tech4242
  • 2,348
  • 2
  • 23
  • 33
  • But what about the back arrow? It is missing? – MJQZ1347 Aug 21 '16 at 18:21
  • @MJQZ1347 Just add "<" to the title and play around with the font? Or check this out: http://stackoverflow.com/a/18874211/6597361 But either way it's a very easy way out of your situation – tech4242 Aug 21 '16 at 18:23
  • 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? – MJQZ1347 Aug 21 '16 at 18:25
  • @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. – tech4242 Aug 21 '16 at 18:41
  • Yeah, probably. Please see my updated question, there are maybe better workarounds to make the navigation bar refresh. – MJQZ1347 Aug 21 '16 at 18:44
  • @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" – tech4242 Aug 21 '16 at 18:49