32

Using SwiftUI how do I change the navigation bar's title size? Choosing between a standard or a large title.

Difference between a large and a standard (inline) title

Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
Clément Cardonnel
  • 4,232
  • 3
  • 29
  • 36

3 Answers3

56

SwiftUI (iOS 14+)

NavigationView {
    TopLevelView {
        // […]
    }
    .navigationBarTitleDisplayMode(.inline) // ⬅️ Important part
}

SwiftUI (Xcode 11.3)

SwiftUI navigationBarTitle modifier has an optional displayMode property which you can set to .inline for small titles and .large for large titles. See documentation

NavigationView {
    TopLevelView {
        // […]
    }
    .navigationBarTitle("Test", displayMode: .inline) // ⬅️ Important part
}

How it's done in UIKit

Since iOS 11, UINavigationBar can display its title in standard and large title mode.

On UIKit, if you want to choose between the two behaviors you have to set the largeTitleDisplayMode property of your ViewController's navigationItem to decide if this particular view controller should display a large title or not.

Then, you need to check the prefersLargeTitle property of your Navigation Controller's navigationBar. Setting it to true will allow the ViewControllers in its navigation stack to display large titles. Conversely, setting it to false will prevent it, overriding the preference of the individual NavigationItems present in the stack.

This will display a large title in UIKit

// Set this property to true to allow NavigationItems to display large titles
let navigationController = UINavigationController()
navigationController.navigationBar.prefersLargeTitles = true

/*
 Choose between `always`, `never` and `automatic` to decide
 if this particular view controller should display a large title.
 */
let viewController = UIViewController()
viewController.navigationItem.largeTitleDisplayMode = .always
Clément Cardonnel
  • 4,232
  • 3
  • 29
  • 36
  • 5
    `.navigationBarTitle(displayMode:)` has been deprecated and seems not to be working in Xcode 12.0 beta 6. -_- There's a new method, `navigationBarTitleDisplayMode(_ displayMode:)` but only available iOS 14 and up. – Natanel Aug 31 '20 at 15:42
  • 1
    hey @Natanel, also bumped on that. What do you think we can do for iOS < 14? – Gonçalo Gaspar Sep 01 '20 at 20:08
  • @GonçaloGaspar it's possible to use something as detailed here, https://stackoverflow.com/a/58427754/3058601, but in my experience it behaves quite strangely and not smoothly. I was trying the have the fist controller on the stack use a large title but the next one inline. It only changed to inline after it already showed a large title. – Natanel Sep 02 '20 at 15:05
  • 2
    @GonçaloGaspar I realized all you need to do is wrap the title string in `Text` and it should work. – Natanel Sep 13 '20 at 14:41
5

For iOS 14 and up

Use the modifier navigationBarTitleDisplayMode(:) on the root view in your navigation stack.

Matthew Quiros
  • 13,385
  • 12
  • 87
  • 132
1

Xcode 14.0+

The most robust approach is to create your own method with default value .large. For that you need a View extension. Keep using the navigationBarTitle() modifiers and along with that use your own ones. If you don't need the default value use .inline instead.

import SwiftUI

extension View {        
    func barTitle(_ title: String,
             size: NavigationBarItem.TitleDisplayMode = .large) -> some View {
        self.navigationBarTitle(title, displayMode: size)
    }
}

struct Benchmark: Identifiable, Hashable {
    let id = UUID()
    var name: String
}

In Xcode 14.0+, there is a new entity called NavigationStack. NavigationStack is a view that displays a root view and enables you to present additional views over the root view.

enter image description here

struct OilView: View {
    
    var benchmarks: [Benchmark] = [ .init(name: "WTI"),   .init(name: "Brent"),
                                    .init(name: "Urals"), .init(name: "OPEC") ]
    var body: some View {
        
        NavigationStack {
            
            List(benchmarks) { benchmark in

                NavigationLink(benchmark.name, value: benchmark)
            }
            .navigationDestination(for: Benchmark.self) { crudeOil in

                if crudeOil.name == "WTI" || crudeOil.name == "Brent" {
                    Text("Light and Sweet")
                        .font(.title2)
                        .barTitle(crudeOil.name)    // default `.large` value
                    
                } else if crudeOil.name == "Urals" || crudeOil.name == "OPEC" {
                    Text("Heavy and Sour")
                        .font(.title2)
                        .barTitle(crudeOil.name, size: .inline)
                }
            }
        }
        .navigationBarTitle("Benchmarks", displayMode: .large)
    }
}

enter image description here

Andy Jazz
  • 49,178
  • 17
  • 136
  • 220