Add subtitle under the title in navigation bar controller in Xcode

31,930

Solution 1

Though there is a solution but it has some known issues

Solution is writing a function like this

func setTitle(title:String, subtitle:String) -> UIView {
    let titleLabel = UILabel(frame: CGRectMake(0, -2, 0, 0))

    titleLabel.backgroundColor = UIColor.clearColor()
    titleLabel.textColor = UIColor.grayColor()
    titleLabel.font = UIFont.boldSystemFontOfSize(17)
    titleLabel.text = title
    titleLabel.sizeToFit()

    let subtitleLabel = UILabel(frame: CGRectMake(0, 18, 0, 0))
    subtitleLabel.backgroundColor = UIColor.clearColor()
    subtitleLabel.textColor = UIColor.blackColor()
    subtitleLabel.font = UIFont.systemFontOfSize(12)
    subtitleLabel.text = subtitle
    subtitleLabel.sizeToFit()

    let titleView = UIView(frame: CGRectMake(0, 0, max(titleLabel.frame.size.width, subtitleLabel.frame.size.width), 30))
    titleView.addSubview(titleLabel)
    titleView.addSubview(subtitleLabel)

    let widthDiff = subtitleLabel.frame.size.width - titleLabel.frame.size.width

    if widthDiff < 0 {
        let newX = widthDiff / 2
        subtitleLabel.frame.origin.x = abs(newX)
    } else {
        let newX = widthDiff / 2
        titleLabel.frame.origin.x = newX
    }

    return titleView
}

Using this function for custom navigation title view in viewDidLoad

self.navigationItem.titleView = setTitle("Title", subtitle: "SubTitle")

Only known issue is that if subtitle becomes very large than the misplacement occurs.

Final Outcome enter image description here

Source: https://gist.github.com/nazywamsiepawel/0166e8a71d74e96c7898

Solution 2

Here is my version using a stack view on an extension.

extension UINavigationItem {
    func setTitle(title:String, subtitle:String) {
        
        let one = UILabel()
        one.text = title
        one.font = UIFont.systemFont(ofSize: 17)
        one.sizeToFit()
        
        let two = UILabel()
        two.text = subtitle
        two.font = UIFont.systemFont(ofSize: 12)
        two.textAlignment = .center
        two.sizeToFit()
        
        let stackView = UIStackView(arrangedSubviews: [one, two])
        stackView.distribution = .equalCentering
        stackView.axis = .vertical
        stackView.alignment = .center
        
        let width = max(one.frame.size.width, two.frame.size.width)
        stackView.frame = CGRect(x: 0, y: 0, width: width, height: 35)
        
        one.sizeToFit()
        two.sizeToFit()
        
        self.titleView = stackView
    }
}

Solution 3

@iosjillian's Swift 4 extension works great, adding a bit more to honor the bar's appearance and user font preferences:

import UIKit

extension UINavigationItem {

  func setTitle(_ title: String, subtitle: String) {
    let appearance = UINavigationBar.appearance()
    let textColor = appearance.titleTextAttributes?[NSAttributedString.Key.foregroundColor] as? UIColor ?? .black

    let titleLabel = UILabel()
    titleLabel.text = title
    titleLabel.font = .preferredFont(forTextStyle: UIFont.TextStyle.headline)
    titleLabel.textColor = textColor

    let subtitleLabel = UILabel()
    subtitleLabel.text = subtitle
    subtitleLabel.font = .preferredFont(forTextStyle: UIFont.TextStyle.subheadline)
    subtitleLabel.textColor = textColor.withAlphaComponent(0.75)

    let stackView = UIStackView(arrangedSubviews: [titleLabel, subtitleLabel])
    stackView.distribution = .equalCentering
    stackView.alignment = .center
    stackView.axis = .vertical

    self.titleView = stackView
  }
}

Solution 4

Thanks a lot for your answer! @RajanMaheshwari

Your coding worked perfectly except the if statement you made with the widthDiff..

I adjusted it a little bit and everything worked smoothly.

if widthDiff < 0 {
        let newX = widthDiff / 2
        subtitleLabel.frame.origin.x = abs(newX)
    } else {
        let newX = widthDiff / 2
        titleLabel.frame.origin.x = newX
    }

Thanks again for your response!

Solution 5

I really liked @user2325031's answer, but found that sizing the labels to fit and setting the frame wasn't needed. I also set the stackView's alignment to .center per @GerardoMR's suggestion.

extension UINavigationItem {

    func setTitle(_ title: String, subtitle: String) {
        let titleLabel = UILabel()
        titleLabel.text = title
        titleLabel.font = .systemFont(ofSize: 17.0)
        titleLabel.textColor = .black

        let subtitleLabel = UILabel()
        subtitleLabel.text = subtitle
        subtitleLabel.font = .systemFont(ofSize: 12.0)
        subtitleLabel.textColor = .gray

        let stackView = UIStackView(arrangedSubviews: [titleLabel, subtitleLabel])
        stackView.distribution = .equalCentering
        stackView.alignment = .center
        stackView.axis = .vertical

        self.titleView = stackView
    }

}
Share:
31,930
AdrianGutierrez
Author by

AdrianGutierrez

Updated on March 28, 2021

Comments

  • AdrianGutierrez
    AdrianGutierrez about 3 years

    So I'm wanting to add a "subtitle" under the title in the navigation bar in navigation controller.

    Mostly everything I look up so far wants me to use CGRect. I don't know a whole lot what that is and it sounds like its wanting me to create an entire new view which is not what I am wanting to do.

    My question is, is there a dot method to adding a subtitle view easily?

    The closest thing I found was posted on stack overflow and here is the link:

    Create a subtitle in navigationbar

    Apparently last year this worked but now I am getting errors and it's in my viewDidLoad...

    I tried this:

    self.navigationController?.navigationItem.prompt = "Subtitle Here"

    It's the only thing that won't show any errors but still doesn't work. It literally does nothing. At least nothing visible at run time.

    On a side note, swift is preferred. Thanks!

  • AdrianGutierrez
    AdrianGutierrez over 7 years
    Its a whole lot more code then i was expecting but it does work. I really hope Apple adds an easier way. Subtitle doesn't seem like anything that would be so far fetched.. lol
  • AdrianGutierrez
    AdrianGutierrez over 7 years
    Thanks a ton by the way! :) @rajan
  • cloudcal
    cloudcal over 7 years
    Great fix! Had to do this as well.
  • Ashu
    Ashu over 7 years
    I need something like this, If title is blank then title should in center. I have to implement in chat app. If user starts typing, then subtitle show. For more see whatsApp.
  • Nitish Makhija
    Nitish Makhija almost 7 years
    title and subtitle slide to centre from left when pushing from navigation controller any workarounds
  • GerardoMR
    GerardoMR almost 7 years
    To me, this is the cleaner answer, it doesn't have magic numbers as the first answer. I will only add stackView.alignment = .center after you set the axis, otherwise it will not appear totally centered if the subtitle is bigger. Also I would remove the last two calls to sizeToFit(), since you called them on the labels.
  • Zoom
    Zoom almost 7 years
    title and subtitle slide to centre from left when pushing from navigation controller any workarounds @naveed
  • Naveed Ahmad
    Naveed Ahmad almost 7 years
    above solution work for centering the both text, in my case its working
  • Yasir
    Yasir almost 7 years
    Having the same issue as @Zoom, from other posts it looks like it may be related to when in the view lifecycle the title is updated?
  • Zoom
    Zoom almost 7 years
    @Yasir adding the code for title and subtitle in viewDidAppear worked for me.
  • Yasir
    Yasir almost 7 years
    My issue was fixed, keeping the initial update coming async from viewDidLoad. It was setting the titleView to an attributed label multiple times as the content changed during transition in. Got it working by only setting the view once, then only updating its contents if already present.
  • lemon lime pomelo
    lemon lime pomelo over 6 years
    as per @GerardoMR comment above -- you can center title/subtitle using the UIStackView setting: stackView.alignment = .center
  • Dilip Tiwari
    Dilip Tiwari about 5 years
    how can i change alignment of both above to be left only
  • Dilip Tiwari
    Dilip Tiwari about 5 years
    i tried titleLabel.textColor = UIColor.white but not working for me
  • user155
    user155 about 5 years
    does default title also has constant font value 17?