3

I have the same problem as described in navigationtitle too long in swiftui -- I want to scale down my navigation bar title to fit the available space. Here's the problem:

Navigation title too long

Here's my code, which incorporates the suggestion made in the answer to the other referenced question:

struct AboutView: View {
    @Binding var showAboutView: Bool
    
    var body: some View {
        NavigationView {
            Form {
                Section() {
                    Text("A placeholder for information about this app.\n\nDetails forthcoming....")
                }
                
                if let url = URL(string: "mailto:sarjo@sarjosoftware.com?subject=My+Wonderful+App") {
                    Section() {
                        Link("Contact the Author", destination: url)
                    }
                }
            }
            // *** suggested solution ***
            .navigationTitle(Text("About My Wonderful App").minimumScaleFactor(0.5).lineLimit(1))
            .navigationBarItems(trailing: Button(action: {
                showAboutView = false
            }) {
                Text("Done").bold()
            })
        }
    }
}

But this code fails to build with the error: Instance method 'navigationTitle' requires that 'some View' conform to 'StringProtocol' on the line Form {. If I move the modifiers on the title text outside to apply to the navigationTitle modifier itself, as shown here:

.navigationTitle(Text("About My Wonderful App")).minimumScaleFactor(0.5).lineLimit(1)

this code builds and runs, but the modifiers are not applied to the title text but to the body text beginning "A placeholder for :

Scaling applied to body text

Thanks for any suggestions.

jayboh
  • 267
  • 3
  • 12

3 Answers3

1

You can try .toolbar especially because .navigationBarItems is deprecated

struct AboutView: View {
    @Binding var showAboutView: Bool
    
    var body: some View {
        NavigationView {
            Form {
                Section() {
                    Text("A placeholder for information about this app.\n\nDetails forthcoming....")
                }
                
                if let url = URL(string: "mailto:sarjo@sarjosoftware.com?subject=My+Wonderful+App") {
                    Section() {
                        Link("Contact the Author", destination: url)
                    }
                }
            }
            .toolbar(content: {
                ToolbarItem(placement: .principal, content: {
                    Text("About My Wonderful App")
                        .font(.title2).fontWeight(.bold)
                })
                
                ToolbarItem(placement: .navigationBarTrailing, content: {
                    Button(action: {showAboutView = false}) {
                        Text("Done").bold()
                    }
                })
            })
        }
    }
}
lorem ipsum
  • 21,175
  • 5
  • 24
  • 48
  • This is partway to what I need. The problem is that the "Done" button appears on the same line as the title string ("About ..."). I'd prefer it above the title string as in the original screenshots, but I don't see a way to do that using .placement. – jayboh Jun 06 '21 at 01:01
  • No `placement` is like `.inline` maybe Monday – lorem ipsum Jun 06 '21 at 01:34
1

I read your problem. my suggestion is to reduce the font size of NavigationTitle you can reduce your NavigationTitle by this Code :

  init() {
    // this is not the same as manipulating the proxy directly
    let appearance = UINavigationBarAppearance()
    
    // this overrides everything you have set up earlier.
    appearance.configureWithTransparentBackground()
    
    // this only applies to big titles
    appearance.largeTitleTextAttributes = [
        .font : UIFont.systemFont(ofSize: 30),
        NSAttributedString.Key.foregroundColor : UIColor.black
    ]
    // this only applies to small titles
    appearance.titleTextAttributes = [
        .font : UIFont.systemFont(ofSize: 20),
        NSAttributedString.Key.foregroundColor : UIColor.black
    ]
    
    //In the following two lines you make sure that you apply the style for good
    UINavigationBar.appearance().scrollEdgeAppearance = appearance
    UINavigationBar.appearance().standardAppearance = appearance
    
    // This property is not present on the UINavigationBarAppearance
    // object for some reason and you have to leave it til the end
    UINavigationBar.appearance().tintColor = .black
    
}

you should add this code upper the body.


also, I attached two links for helping you out of NavigationTitle. I hope these are useful for you.

Apple hackingwithswift

  • Thank-you, this works nicely. I did remove the configureWithTransparentBackground() to match the styling of SwiftUI's NavigationStack that I'm using. – Marcy Jan 11 '23 at 06:23
1

Tested on SwiftUI's NavigationView and NavigationStack.

This answer is derived from Amirreza Jolani's answer which is also similar to the code provided from "Customizing SwiftUI Navigation Bar". I thought some additional explanation might help.

The following function formats the singleton UINavigationBar and takes in the title and large titles' desired font sizes:

func formatNavTitle(_ fontSize: CGFloat, _ largeFontSize: CGFloat) {

    let appearance = UINavigationBarAppearance()
    
    appearance.largeTitleTextAttributes = [
        .font : UIFont.systemFont(ofSize: largeFontSize),
        NSAttributedString.Key.foregroundColor : UIColor.label
    ]
    
    appearance.titleTextAttributes = [
        .font : UIFont.systemFont(ofSize: fontSize),
        NSAttributedString.Key.foregroundColor : UIColor.label
    ]
    
    UINavigationBar.appearance().scrollEdgeAppearance = appearance
    UINavigationBar.appearance().standardAppearance = appearance
    UINavigationBar.appearance().tintColor = .label
}

Usage: formatNavTitle(20, 30)

Features that shrink text such as minimumScaleFactor and tightening are limited to UILabel and SwiftUI's Text. Unfortunately those features don't appear to be available with UINavigationBar which uses NSAttributedString. And SwiftUI's navigation title appears to be part of a wrapper around UINavigationBar.

But the font size can be adjusted for the regular title and the large title using the function above. After adding the function to the app, an init statement in this example was also added to the main entrypoint of the app although could be added to AboutView instead:

@main
struct myExampleApp: App {
    
    init() { formatNavTitle(20, 30) }
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

This results in the large title being 30 points and the regular title being 20 points: enter image description here

Marcy
  • 4,611
  • 2
  • 34
  • 52