17

I'm using SwiftUI with Xcode 11 and I want to change NavigationBarTitle font with these lines of codes:

.navigationBarTitle (Text("Navigation Bar Title"), displayMode: .inline)
    .font(.subheadline)

but nothing happened. any suggestion or comment?

Mojtaba Hosseini
  • 95,414
  • 31
  • 268
  • 278
Sajjad
  • 1,536
  • 2
  • 17
  • 31

6 Answers6

22

In SwiftUI, at this point we can not change the navigationBarTitle font directly, but you can change navigationBar appearance like this,

struct YourView: View {
    init() {
        //Use this if NavigationBarTitle is with Large Font
        //UINavigationBar.appearance().largeTitleTextAttributes = [.font : UIFont(name: "Georgia-Bold", size: 20)!]

        //Use this if NavigationBarTitle is with displayMode = .inline
        UINavigationBar.appearance().titleTextAttributes = [.font : UIFont(name: "Georgia-Bold", size: 20)!]
    }
    var body: some View {
        NavigationView {
            Text("Hello World!")
            //.navigationBarTitle("TEST")
            .navigationBarTitle (Text("TEST"), displayMode: .inline)
        }
    }
}

I hope it will help you. Thanks!!

Anjali Kevadiya
  • 3,567
  • 4
  • 22
  • 43
3

You can't change navigationBarTitle's font with .font modifier yet (Tested in Xcode 11-Beta2).

But you can build your own custom navigationBarView with complete access to any of its subviews like this:

struct NavigationBarView: View {

    var body: some View {

        VStack(spacing: 0) {
            Rectangle()
                .foregroundColor(Style.Color.navigationBarColor)
                .edgesIgnoringSafeArea(.top)
                .frame(height: 0)

            Rectangle()
                .foregroundColor(Style.Color.navigationBarColor)
                .frame(height: 64)
            .overlay(
                HStack() {
                    Image("close")
                    Spacer()

                    Text("سفر به سلامت")
                        .font(Style.Font.navigationTitle)
                        .color(Style.Color.darkTextColor)
                        .multilineTextAlignment(.center)

                    Spacer()
                    Image("menu")
                }
            )

            Spacer()
        }
        .edgesIgnoringSafeArea(.horizontal)
    }
}

Note that you will lose LargeTitleStyle with this implementation.

amodrono
  • 1,900
  • 4
  • 24
  • 45
Mojtaba Hosseini
  • 95,414
  • 31
  • 268
  • 278
3

I think you have to create a NavigationBarBuilder.

struct NavigationBarBuilder: UIViewControllerRepresentable {

    var build: (UINavigationController) -> Void = { _ in }

    func makeUIViewController(context: UIViewControllerRepresentableContext<NavigationBarBuilder>) -> UIViewController {

        UIViewController()
    }

    func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<NavigationBarBuilder>) {

        if let navigationController = uiViewController.navigationController{
            self.build(navigationController)
        }
    }
}

and you can use it in your content view.

struct ContentView: View {
    var body: some View {
        NavigationView {
            Text("")
                .navigationBarTitle("Türkiye", displayMode: .inline)
                .background(NavigationBarBuilder {navigationController in
                    navigationController.navigationBar.barTintColor = .red
                    navigationController.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.white]
                })
        }
        .navigationViewStyle(StackNavigationViewStyle())
    }
}

Good luck...

Erkam KUCET
  • 485
  • 8
  • 21
2

In SwiftUI 5 UINavigationBar.appearance().titleTextAttributes doesn't work. You need to use one of the following to change the font in the title:

        init () {
            UINavigationBar.appearance().largeTitleTextAttributes = [.font : UIFont(name: "Georgia", size: 20)!]
            // OR
            UINavigationBar.appearance().largeTitleTextAttributes = [.font:UIFont.preferredFont(forTextStyle:.text-style)]
        }

where .text-style could be found in UIFont.TextStyle documentation, e.g.

.caption
.body
.title1
.title2
.title3
etc

Update 1 (to answer a qs about exact code in comments)

struct ContentView: View {

    init () {
        let paragraph = NSMutableParagraphStyle()
        paragraph.alignment = .center
        
        UINavigationBar.appearance().largeTitleTextAttributes = [.font:UIFont.preferredFont(forTextStyle:.title2),
                                                                 .foregroundColor:UIColor.systemBlue,
                                                                 .paragraphStyle: paragraph
                                                                ]

...

then in body I have this. You should probably pay attention to displayMode param

// Body is in the same ContentView struct. Settings from init will be used in navigationBarTitle
// listView() is just a custom function returning a SwiftUI's List()

var body: some View {


        NavigationView {
            
        listView()
            .navigationBarTitle(
                Text(self.accts.selCount <= 0 ? "Accounts" : "\(self.accts.selCount) selected")
                ,
                displayMode:.large)
Oleg Gryb
  • 5,122
  • 1
  • 28
  • 40
  • I'm not seeing this work. Tried in parent NavigationView's init and in child views. Can you share a brief example of exactly where this init is? – Ryan May 29 '21 at 02:27
  • thanks, but I'm not sure I follow. The last block has a ViewBuilder body with three AnyViews and a TabView with an interior Navigation View. It's not clear where the init would be placed... in the view produced by func listView or something else. Can you write as a single buildable View struct? I do see the global override method working: https://stackoverflow.com/a/67172529/14433738 – Ryan May 29 '21 at 23:50
  • @Ryan That's very standard. 'init' is a constructor of some "struct ContentView: View...". ContentView is used in SceneDelegate.scene function to setup initial view. 'var body' defines content's UI in the same ContentView struct. Not sure what is confusing. Both init and 'var body' are defined in the same ContentView class. In the body you need to pay attention to only one thing: navigationBarTitle – Oleg Gryb May 30 '21 at 03:53
  • Updated the answer a bit to make clear that both 'init' and 'var body' are in the same ContentView struct, which is a root of all views. – Oleg Gryb May 30 '21 at 04:01
  • The comment helps clarify the intent. Just FYI from a reader who has made some material apps with SwiftUI, the code formatting/syntax has all sorts of oddness with a split up ternary and parentheses and brackets perhaps mixed up or not copied in, which made some guesswork at what was happening. Maybe it's SO doing something with the paste-in. Thanks for the proposed solution route and taking the time to edit this, though. – Ryan May 30 '21 at 05:07
  • Yes, formatting was not good. I've simplified the second part by removing unnecessary details. Hope readability is better now – Oleg Gryb May 30 '21 at 05:17
0

In my case the above answers did not work. But the code below worked fine.

let appearance = UINavigationBarAppearance()
        
appearance.titleTextAttributes = [.font : UIFont(name: "Georgia-Bold", size: 20)!]
Taeeun Kim
  • 964
  • 1
  • 8
  • 20
0

Try adding Navigation title like below and enjoy. tested in [Xcode 14.3 - ios 16.4]

NavigationView { // <1>
    Text("Hello, SwiftUI!")
        .navigationBarTitleDisplayMode(.inline)
        .toolbar { // <2>
            ToolbarItem(placement: .principal) { // <3>
                VStack {
                    Text("Title").font(.headline)
                    Text("Subtitle").font(.subheadline)
                }
            }
        }
}
Aaban Tariq Murtaza
  • 1,155
  • 14
  • 16