web-dev-qa-db-fra.com

Ajouter un sous-titre sous le titre dans le contrôleur de la barre de navigation dans Xcode

Je souhaite donc ajouter un "sous-titre" sous le titre dans la barre de navigation du contrôleur de navigation.

Pour l’essentiel, tout ce que j’ai levé jusqu’à présent veut que j’utilise CGRect. Je ne sais pas trop ce que c'est et cela ressemble à sa volonté de me créer une toute nouvelle vue, ce qui n'est pas ce que je veux faire.

Ma question est la suivante: existe-t-il une méthode de points pour ajouter facilement une vue de sous-titres?

La chose la plus proche que j'ai trouvée a été postée sur le débordement de la pile et voici le lien:

Créer un sous-titre dans la barre de navigation

Apparemment, l'année dernière, cela a fonctionné, mais maintenant je reçois des erreurs et c'est dans mon point de vue ...

J'ai essayé ceci:

self.navigationController? .navigationItem.Prompt = "Sous-titre ici"

C'est la seule chose qui ne montre aucune erreur mais qui ne fonctionne toujours pas. Il ne fait littéralement rien. Au moins rien de visible au moment de l'exécution.

Sur une note de côté, Swift est préféré. Merci!

29
AdrianGutierrez

Bien qu'il existe une solution, mais il a quelques problèmes connus

Solution écrit une fonction comme celle-ci

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
}

Utilisation de cette fonction pour l’affichage du titre de navigation personnalisé dans viewDidLoad

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

Le seul problème connu est que si le sous-titre devient très volumineux, le mauvais placement se produit.

Résultat final  enter image description here

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

43
Rajan Maheshwari

Voici ma version utilisant une vue de pile sur une 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

            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
        }
    }
50
user2325031

Merci beaucoup pour votre réponse! @ RajanMaheshwari 

Votre codage a parfaitement fonctionné, sauf la déclaration if que vous avez faite avec widthDiff.

Je l'ai ajusté un peu et tout s'est bien passé.

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

Merci encore pour votre réponse!

11
AdrianGutierrez

L'extension Swift 4 de @ iosjillian fonctionne parfaitement, en ajoutant un peu plus pour honorer l'apparence de la barre et les préférences de police de l'utilisateur:

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
  }
}
3
Dan

Si vous recherchez un code Objective-C de la solution susmentionnée 

    UILable *title = [[UILabel alloc]init];
    UILabel *subtitle = [[UILabel alloc]init];

   [title setFont:[UIFont systemFontOfSize:12]];
   [title setTextColor:[UIColor whiteColor]];
   [title setFont:[UIFont systemFontOfSize:17]];
   [title sizeToFit];
   title.text = @"Title";

   [subtitle setTextColor:[UIColor whiteColor]];
   [subtitle setFont:[UIFont systemFontOfSize:12]];
   [subtitle setTextAlignment:NSTextAlignmentCenter];
   [subtitle sizeToFit];
   subtitle.text = @"Subtitle Title";

   UIStackView *stackVw = [[UIStackView alloc]initWithArrangedSubviews:@[title,subtitle]];
   stackVw.distribution = UIStackViewDistributionEqualCentering;
   stackVw.axis = UILayoutConstraintAxisVertical;
   stackVw.alignment =UIStackViewAlignmentCenter;


   [stackVw setFrame:CGRectMake(0, 0, MAX(title.frame.size.width, subtitle.frame.size.width), 35)];
   self.navigationItem.titleView = stackVw;
3
Mubeen Qazi

Merci pour la réponse @RajanMaheshwari

Si quelqu'un a le problème où le titre est mal aligné lorsque le texte du sous-titre est plus long que le texte du titre, j'ai ajouté le code suivant à la réponse de Rajan ci-dessous, juste en dessous du libellé subtitleLabel:

// Fix incorrect width bug
if (subtitleLabel.frame.size.width > titleLabel.frame.size.width) {
    var titleFrame = titleLabel.frame
    titleFrame.size.width = subtitleLabel.frame.size.width
    titleLabel.frame = titleFrame
    titleLabel.textAlignment = .center
}

J'espère que cela aide quelqu'un qui a rencontré le même problème que moi

2
Nick Kirsten

Swift 4:

import UIKit

class NavigationTitleView: UIView {

    private var contentStackView = UIStackView()
    private var titleLabel = UILabel()
    private var subTitleLabel = UILabel()

    override init(frame: CGRect) {
        super.init(frame: frame)

        viewConfig()
        addViewsConfig()
        layoutViewsConfig()

    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }


    func set(title: String, subTitle: String){

        self.titleLabel.text = title
        self.subTitleLabel.text = subTitle

    }

    private func viewConfig() {

        contentStackView.axis = .vertical
        contentStackView.alignment = .center
        contentStackView.distribution  = .fill
        contentStackView.spacing = 5


        self.backgroundColor = .clear
        self.titleLabel.textColor = .white
        self.self.subTitleLabel.textColor = .white

    }

    private func addViewsConfig() {

        contentStackView.addArrangedSubview(subTitleLabel)
        contentStackView.addArrangedSubview(titleLabel)
        self.addSubview(contentStackView)

    }

    private func layoutViewsConfig(){

        contentStackView.translatesAutoresizingMaskIntoConstraints = false
        contentStackView.centerXAnchor.constraint(equalTo: self.centerXAnchor, constant: 0.0).isActive = true
        contentStackView.centerYAnchor.constraint(equalTo: self.centerYAnchor, constant: 0.0).isActive = true

    }

}

Utilisation:

import UIKit

class  ViewController: UIViewController {

    private var navigationTitleView = NavigationTitleView()

    override func viewDidLoad() {
        super.viewDidLoad()

        self.navigationItem.titleView = navigationTitleView
        navigationTitleView.set(title: "title", subTitle: "subTitle")

    }

}

 enter image description here

1
Mohammad Razipour

Une autre solution, utilisant uniquement les étiquettes one et NSAttributedString pour différencier le titre du sous-titre (avec différentes tailles de police, poids, couleurs, etc.). Supprime le problème de l'alignement différent des étiquettes. 

extension UIViewController {
    func setTitle(_ title: String, subtitle: String) {
        let rect = CGRect(x: 0, y: 0, width: 400, height: 50)
        let titleSize: CGFloat = 20     // adjust as needed
        let subtitleSize: CGFloat = 15

        let label = UILabel(frame: rect)
        label.backgroundColor = .clear
        label.numberOfLines = 2
        label.textAlignment = .center
        label.textColor = .black

        let text = NSMutableAttributedString()
        text.append(NSAttributedString(string: title, attributes: [.font : UIFont.boldSystemFont(ofSize: titleSize)]))
        text.append(NSAttributedString(string: "\n\(subtitle)", attributes: [.font : UIFont.systemFont(ofSize: subtitleSize)]))
        label.attributedText = text
        self.navigationItem.titleView = label
    }
}

TitleView personnalisé basé en partie sur https://stackoverflow.com/a/34298491/3918865

1
florianpfisterer

J'ai bien aimé la réponse de @ user2325031, mais j'ai constaté qu'il n'était pas nécessaire de dimensionner les étiquettes pour l'adapter et de définir le cadre. J'ai également défini l'alignement de stackView sur .center selon la suggestion de @ GerardoMR.

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
    }

}
0
iosjillian