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

5

17

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?

Earwitness answered 6/11, 2017 at 22:4 Comment(1)
Did you find a solution?Fike
J
23

All you need is:

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

Working also with SwiftUI on iOS 15.

Jimmyjimsonweed answered 18/7, 2021 at 11:50 Comment(2)
Worked for me on iOS 14.Punchy
This works great while I'm not using Swift UI but good old .xib with interface builder, tested on iOS 15.2. Thanks!Blanchette
F
22

This is the workaround that I found

override func viewDidLoad() {
  super.viewDidLoad()

  title = yourTitle
  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: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: fontSize)]).width

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

    navigationController?.navigationBar.largeTitleTextAttributes =
        [NSAttributedStringKey.font: UIFont.boldSystemFont(ofSize: fontSize)
    ]
  }
}
Fike answered 3/3, 2018 at 9:58 Comment(4)
this works great ! the only change I'd make is to replace the last line with the following(Swift 3 syntax ahead): if var titleAttributes = navigationController?.navigationBar.largeTitleTextAttributes { titleAttributes[NSFontAttributeName] = UIFont.boldSystemFont(ofSize: fontSize) navigationController?.navigationBar.largeTitleTextAttributes = titleAttributes } This retains the title's original attributes whilst only modifying the font size. Finally.. one may need to use guard let title = self.navigationItem.title depending on how they've set it.Horsecar
This should be the accepted answer. Not sure why the other one is. With a few tweaks of code for swift 3+, this works great.Karoline
I would also recommend taking a max() comparison of the calculated font size vs. a given required minimum. For very long titles, the font keeps getting infinitely small to accommodate this code. So just before you pass fontSize to the navigation bar, do this to make sure that the minimum font size never gets less than 14 points: let minFontSize = max(fontSize, 14). Then, pass minFontSize to the navigation bar.Karoline
Bravo. Works like a charm. 👍🏻 (Xcode 11.4.1 + iOS 13.3)Bootless
N
3

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.

Negate answered 6/11, 2017 at 22:41 Comment(4)
It just adds the label on top of the large title, so now basically I have two titles. So, I have to choose between the two types of titles. But itself it works. Thanks for the answer.Earwitness
Yes, but in that case I don't have the animation of large titlesEarwitness
Same here, this add a new separate title on top over the Large TitleArmanda
@TigranIskandaryan - many of the people reading this question are going to need a solution for the normal use of Large Titles. They will scroll up and down enough to trigger the two types of title display.Strut
L
0

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()

Lewie answered 2/6, 2021 at 9:56 Comment(0)
R
-1

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)
    ]
}

}

Ritenuto answered 18/11, 2019 at 13:30 Comment(1)
Please explain what exactly was the edit and how it improves the original answer.Fourcycle

© 2022 - 2024 — McMap. All rights reserved.