My navigation bar's large title is too wide. How to fix that?

Viewed 7582

I am using navigation controller, and I've set to true its navigation bar's prefersLargeTitle property. Everything works fine, but when the text of my title becomes too big, it doesn't fit in space. Here how it looks:

enter image description here

Is it possible to somehow make the title (while the navigation bar's prefersLargeTitle property is set to true) dynamically adjust its font size, and if it is so, how to achieve that?

5 Answers

All you need is:

UILabel.appearance(whenContainedInInstancesOf: [UINavigationBar.self]).adjustsFontSizeToFitWidth = true

Working also with SwiftUI on iOS 15.

This question is somewhat answered here: How to resize Title in a navigation bar dynamically.

self.title = "Your TiTle Text"
let tlabel = UILabel(frame: CGRectMake(0, 0, 200, 40))
tlabel.text = self.title
tlabel.textColor = UIColor.whiteColor()
tlabel.font = UIFont(name: "Helvetica-Bold", size: 30.0)
tlabel.backgroundColor = UIColor.clearColor()
tlabel.adjustsFontSizeToFitWidth = true
self.navigationItem.titleView = tlabel

That being said, this is slightly different, in that you have the prefersLargeTitle property set. Now, I am not sure whether the tlabel.adjustsFontSizeToFitWidth = true overrides the prefersLargeTitle property, but try it out and see if it works. There is also some additional information regarding navigation item large titles here: https://developer.apple.com/documentation/uikit/uinavigationitem/2909056-largetitledisplaymode. Hope this helps.

Tested for iOS12 ~ iOS14

extension UINavigationController {

    func adjustFontSize(with title: String) {
        let insetToEdge: CGFloat = 16
        let maxWidth = navigationBar.bounds.width - insetToEdge - insetToEdge
        let largeTitleFont = UIFont.preferredFont(forTextStyle: .largeTitle)
        var fontSize = largeTitleFont.pointSize

        var largeTitleTextAttributes: [NSAttributedString.Key: Any] = [:]

        var largeTitleSize: CGSize
        if #available(iOS 13.0, *) {
            largeTitleSize = NSAttributedString(
                string: title,
                attributes: navigationBar.standardAppearance.largeTitleTextAttributes)
                .size()
        } else {
            largeTitleTextAttributes = [NSAttributedString.Key.font: largeTitleFont]
            largeTitleSize = NSAttributedString(
                string: title,
                attributes: largeTitleTextAttributes)
                .size()
        }
        guard largeTitleSize.width > maxWidth else { return }
        while largeTitleSize.width > maxWidth {
            fontSize -= 1
            if #available(iOS 13.0, *) {
                largeTitleTextAttributes = navigationBar.standardAppearance.largeTitleTextAttributes
            }
            largeTitleTextAttributes[NSAttributedString.Key.font] = UIFont.BO.font(
                ofSize: fontSize,
                weight: .semiBold)
            largeTitleSize = NSAttributedString(
                string: title,
                attributes: largeTitleTextAttributes)
                .size()
        }
        if #available(iOS 13.0, *) {
            navigationBar.standardAppearance.largeTitleTextAttributes = largeTitleTextAttributes
        } else {
            navigationBar.largeTitleTextAttributes = largeTitleTextAttributes
        }
    }

}

call from viewDidLoad()

Made an edit to @vicente.fava answer - this works great.

self.title = longTitle
self.navigationController?.navigationBar.prefersLargeTitles = true
adjustLargeTitleSize()


extension UIViewController {
func adjustLargeTitleSize() {
    guard let title = title, #available(iOS 11.0, *) else { return }

    let maxWidth = UIScreen.main.bounds.size.width - 60
    var fontSize = UIFont.preferredFont(forTextStyle: .largeTitle).pointSize
    var width = title.size(withAttributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: fontSize)]).width

    while width > maxWidth {
        fontSize -= 1
        width = title.size(withAttributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: fontSize)]).width
    }

    navigationController?.navigationBar.largeTitleTextAttributes =
        [NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: fontSize)
    ]
}

}

Related