28

I have a UINavigationController with default value of it's navigationBar.prefersLargeTitles = true .

I am switching that to false when I push into a new scene lets call it (DetailsViewController), by changing it into the viewWillDisappear .

override func viewWillDisappear(_ animated: Bool) {
   super.viewWillDisappear(animated)
   navigationController?.navigationBar.prefersLargeTitles = false
}

Now in DetailsViewController I am using willMove(to parent:) .

override func willMove(toParent parent: UIViewController?) {
        navigationController?.navigationBar.prefersLargeTitles = true
}

To transition back to large titles .

Observe the attached snapshots of how iOS 13 doing it with how iOS 12 is doing it, considering iOS 12 is the correct behavior.

iOS 13 :

iOS 13

iOS 12 :

iOS 12

Mohmmad S
  • 5,001
  • 4
  • 18
  • 50
  • You don't have to change `.prefersLargeTitles` at all when pushing a detail view controller to the navigation stack, it will automatically use a small title and then go back to the large one once you get back to the root view controller, as far as I know – henrik-dmg Oct 09 '19 at 09:45
  • @henrik-dmg I'am not sure if it was like that before, but not anymore everything goes to large title if i did so, i have tried that . – Mohmmad S Oct 09 '19 at 09:49
  • 1
    `largeTitleDisplayMode` to .`automatic` and you should get the desired transition. – Harry J Oct 09 '19 at 11:36
  • @HarryJ where ? – Mohmmad S Oct 09 '19 at 11:39
  • Within your viewDidLoad or navigation controller, `navigationController?.navigationItem.largeTitleDisplayMode = .automatic` – Harry J Oct 09 '19 at 11:41
  • yeah, tried that not working . – Mohmmad S Oct 09 '19 at 11:42
  • Have to try to play with dispatch after for put some delay, it looks like animation when pop VC speed in ios13 creating issue. – guru Oct 09 '19 at 13:24
  • @guru i am not sure that would solve it but ill give it a try . – Mohmmad S Oct 10 '19 at 08:37

7 Answers7

92

What you're doing was always wrong. You should set prefersLargeTitles to true once for the navigation bar and never touch it again.

The way to change what each view controller does about large titles as it appears is that that view controller sets its own navigationItem (in its viewDidLoad) to have the desired largeTitleDisplayMode. So if the first v.c. has .always and the second has .never everything will be smooth.

matt
  • 515,959
  • 87
  • 875
  • 1,141
3

Swift 5, Xcode 13:

UIViewController(1) + UINavigationController:

override func viewDidLoad() {
    super.viewDidLoad()

    navigationController?.navigationBar.prefersLargeTitles = true
    navigationItem.title = "Your title here"
}

UIViewController(2 - "i.e.: detailsViewController"):

override func viewDidLoad() {
    super.viewDidLoad()
    
    navigationItem.largeTitleDisplayMode = .never
    navigationItem.title = "Your title here"
}

It works like a charm!

oskarko
  • 3,382
  • 1
  • 26
  • 26
1

I had the same issue and had to place a NavigationItem on the second ViewController's storyboard. My NavigationItem was being created automatically by the segue and its prefersLargeTitle in the viewDidLoad() was not finished creating before the view appeared. Adding a NavigationItem to the storyboard fixed this issue and allowed me to set the prefersLargeTitle in the storyboard's properties menu.

Ben Hardin
  • 21
  • 2
1

In my case this problem was occurring during a segue to a view controller which is a child of a UITabBarController. Setting largeTitleDisplayMode on the child view controller was not enough to fix this bug.

I have solved the issue by adding a navigation item to the UITabBarController scene and setting largeTitleDisplayMode as .never there.

Luke
  • 965
  • 8
  • 21
0

I solved this problem like this:

override func viewWillDisappear(_ animated: Bool) {
    title = ""
}

All ingenious is simple))

0
final class CustomHosting<Content: View>: UIHostingController<Content> {

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.navigationItem.largeTitleDisplayMode = .never
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        self.navigationItem.largeTitleDisplayMode = .automatic
    }
}

I fixed same problem like this :) My problem is presenting SUI Detail Collection view from UIKit Collection, and had some jumping while navigation title changing.

iTux
  • 1,946
  • 1
  • 16
  • 20
0

iOS Large Title

  • call prefersLargeTitles = true only once for NavigavionViewController
  • regulate the size by largeTitleDisplayMode

First ViewController

override func viewDidLoad() {
    super.viewDidLoad()

    self.navigationItem.title = "My Title 1"
    
    //1
    self.navigationController?.navigationBar.prefersLargeTitles = true

    //2
    self.navigationItem.largeTitleDisplayMode = .always
}

Second ViewController

override func viewDidLoad() {
    super.viewDidLoad()

    self.navigationItem.title = "My Title 2"

    //2
    self.navigationItem.largeTitleDisplayMode = .never
}

Looks like:

Some notes

Also take into account that if you set custom leftBarButtonItem image for the second ViewController the transition animation will be different

let backButtonImage = self.image
let backBarButtonItem = UIBarButtonItem(image: backButtonImage, style: .plain, target: self, action: #selector(backClicked))
self.navigationItem.leftBarButtonItem = backBarButtonItem

Looks like:

yoAlex5
  • 29,217
  • 8
  • 193
  • 205