简体   繁体   English

如何在导航栏中设置多行大标题? (iOS 11 的新功能)

[英]How to set multi line Large title in navigation bar? ( New feature of iOS 11)

I am in process of adding large title in navigation bar in one of the application.我正在其中一个应用程序的导航栏中添加大标题。 The issue is title is little long so I will require to add two lines in large title.问题是标题有点长,所以我需要在大标题中添加两行。 How can I add large title with two lines in navigation bar?如何在导航栏中添加两行大标题

This is not about default navigation bar title!这与默认导航栏标题无关! This is about large title which is introduced in iOS 11 .这是关于在 iOS 11 中引入的大标题 So make sure you add suggestions by considering large title.因此,请确保通过考虑大标题来添加建议。 Thanks谢谢

标题文本在导航栏中被 3 个点截断

Based in @krunal answer, this is working for me:基于@krunal 的回答,这对我有用:

extension UIViewController {

func setupNavigationMultilineTitle() {
    guard let navigationBar = self.navigationController?.navigationBar else { return }
    for sview in navigationBar.subviews {
        for ssview in sview.subviews {
            guard let label = ssview as? UILabel else { break }
            if label.text == self.title {
                label.numberOfLines = 0
                label.lineBreakMode = .byWordWrapping
                label.sizeToFit()
                UIView.animate(withDuration: 0.3, animations: {
                    navigationBar.frame.size.height = 57 + label.frame.height
                })
            }
        }
    }
}

In the UIViewController:在 UIViewController 中:

override func viewDidLoad() {
    super.viewDidLoad()
    self.title = "This is a multiline title"
    setupNavigationMultilineTitle()
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    setupNavigationMultilineTitle()
}

And for setting font and color on the large title:并在大标题上设置字体和颜色:

navigation.navigationBar.largeTitleTextAttributes = [NSAttributedStringKey.foregroundColor: .red, NSAttributedStringKey.font: UIFont.boldSystemFont(ofSize: 30)]

Get a navigation item subviews and locate UILabel from it.获取导航项子视图并从中找到 UILabel。

Try this and see:试试这个,看看:

self.navigationController?.navigationBar.prefersLargeTitles = true
self.navigationController?.navigationItem.largeTitleDisplayMode = .automatic

self.title = "This is multiline title for navigation bar"
self.navigationController?.navigationBar.largeTitleTextAttributes = [                     
                                NSAttributedStringKey.foregroundColor: UIColor.black,
                                NSAttributedStringKey.font : UIFont.preferredFont(forTextStyle: .largeTitle)
                                ]

for navItem in(self.navigationController?.navigationBar.subviews)! {
     for itemSubView in navItem.subviews { 
         if let largeLabel = itemSubView as? UILabel {
             largeLabel.text = self.title
             largeLabel.numberOfLines = 0
             largeLabel.lineBreakMode = .byWordWrapping
         }
     }
}

Here is result:这是结果:

在此处输入图片说明

The linebreak solution seems to be problematic when there's a back button.当有后退按钮时,换行解决方案似乎有问题。 So instead of breaking lines, I made the label auto adjust font.因此,我没有断行,而是让标签自动调整字体。

func setupLargeTitleAutoAdjustFont() {
    guard let navigationBar = navigationController?.navigationBar else {
        return
    }
    // recursively find the label
    func findLabel(in view: UIView) -> UILabel? {
        if view.subviews.count > 0 {
            for subview in view.subviews {
                if let label = findLabel(in: subview) {
                    return label
                }
            }
        }
        return view as? UILabel
    }

    if let label = findLabel(in: navigationBar) {
        if label.text == self.title {
            label.adjustsFontSizeToFitWidth = true
            label.minimumScaleFactor = 0.7
        }
    }
}

Then it needs to be called in viewDidLayoutSubviews() to make sure the label can be found, and we only need to call it once:然后需要在 viewDidLayoutSubviews() 中调用以确保可以找到标签,我们只需要调用一次:

private lazy var setupLargeTitleLabelOnce: Void = {[unowned self] in
    if #available(iOS 11.0, *) {
        self.setupLargeTitleAutoAdjustFont()
    }
}()

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    let _ = setupLargeTitleLabelOnce
}

If there's any navigationController pop event back to this controller, we need to call it again in viewDidAppear().如果有任何 navigationController pop 事件返回到这个控制器,我们需要在 viewDidAppear() 中再次调用它。 I haven't found a better solution for this - there's a small glitch of label font changing when coming back from a pop event:我还没有找到更好的解决方案 - 从流行事件回来时,标签字体发生了一个小故障:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    if #available(iOS 11.0, *) {
        setupLargeTitleAutoAdjustFont()
    }
}

If anyone looking for Title Lable Not Large Title, then below code is working.如果有人在寻找Title Lable Not Large Title,那么下面的代码是有效的。

Swift 5.X斯威夫特 5.X

func setMultilineNavigationBar(topText:  String, bottomText : String) {
     let topTxt = NSLocalizedString(topText, comment: "")
     let bottomTxt = NSLocalizedString(bottomText, comment: "")

     let titleParameters = [NSAttributedString.Key.foregroundColor : UIColor.white,
                               NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16, weight: .semibold)]
     let subtitleParameters = [NSAttributedString.Key.foregroundColor : UIColor.white,
                                  NSAttributedString.Key.font : UIFont.systemFont(ofSize: 13, weight: .regular)]

     let title:NSMutableAttributedString = NSMutableAttributedString(string: topTxt, attributes: titleParameters)
     let subtitle:NSAttributedString = NSAttributedString(string: bottomTxt, attributes: subtitleParameters)

     title.append(NSAttributedString(string: "\n"))
     title.append(subtitle)

     let size = title.size()

     let width = size.width
     guard let height = navigationController?.navigationBar.frame.size.height else {return}

      let titleLabel = UILabel(frame: CGRect.init(x: 0, y: 0, width: width, height: height))
      titleLabel.attributedText = title
      titleLabel.numberOfLines = 0
      titleLabel.textAlignment = .center
      self.navigationItem.titleView = titleLabel 
    }

This is working fine for me.这对我来说很好用。 Hope this function will help you.希望这个功能能帮到你。

Happy Coding :)快乐编码:)

Swift 4 : Multi line even though the sentence is only short Swift 4 :多行,即使句子很短

title = "You're \nWelcome"

for navItem in(self.navigationController?.navigationBar.subviews)! {
     for itemSubView in navItem.subviews { 
         if let largeLabel = itemSubView as? UILabel {
             largeLabel.text = self.title
             largeLabel.numberOfLines = 0
             largeLabel.lineBreakMode = .byWordWrapping
         }
     }
}

证明

(Edit 7/13: I notice that this solution is not support scrollView, so now I'm in research) (编辑 7/13:我注意到这个解决方案不支持 scrollView,所以现在我正在研究)

I found a perfect solution on Swift5在 Swift5 上找到了一个完美的解决方案

but sorry for my poor English because I'm Japanese🇯🇵Student.但是对不起我的英语不好,因为我是日本人🇯🇵学生。

In case of 2 lines In case of 3 lines 2行时3行时

At first, set navigation settings for largeTitle normally in viewDidLoad首先在viewDidLoad正常设置largeTitle的导航设置

//Set largeTitle
navigationItem.largeTitleDisplayMode = .automatic
navigationController?.navigationBar.prefersLargeTitles = true
navigationController?.navigationBar.largeTitleTextAttributes = [.font: UIFont.systemFont(ofSize: (fontSize + margin) * numberOfLines)]//ex) fontSize=26, margin=5, numberOfLines=2
        
//Set title
title = "multiple large\ntitle is working!"

It is most important point of this solution that font-size at largeTitleTextAttributes equals actual font-size(+margin) multiplied by number of lines.此解决方案最重要的一点是largeTitleTextAttributes处的字体大小等于实际字体大小(+边距)乘以行数。

Description image描述图片

Because, default specification of navigationBar attributes may be able to display only 1 line largeTitle.因为,navigationBar 属性的默认规范可能只能显示1 行largeTitle。

Although, somehow, I did notice that in case of label-settings(the label which subview of subview of navigationBar) on direct, it can display any number of lines in 1 line of in case of navigationBar attributes .虽然,不知何故,我确实注意到,在直接设置标签设置(导航栏子视图的子视图的标签)的情况下,它可以在导航栏属性的情况下在 1 行中显示任意数量的行

So, we should do set big font in navigationbar attributes, and set small font in the label(subview of subview of navigationBar), and take into consideration the margins.所以,我们应该在导航栏属性中设置大字体,并在标签(导航栏子视图的子视图)中设置小字体,并考虑边距。

Do label settings direct in viewDidAppear like this:像这样直接在viewDidAppear做标签设置:

//Find label
navigationController?.navigationBar.subviews.forEach({ subview in
        subview.subviews.forEach { subsubview in
        guard let label: UILabel = subsubview as? UILabel else { return }
        //Label settings on direct.
        label.text = title
        label.font = UIFont.systemFont(ofSize: fontSize)
        label.numberOfLines = 0
        label.lineBreakMode = .byWordWrapping
        label.sizeToFit()
    }
})

Therefore, in short, the solution at minimum code is given like this:因此,简而言之,最小代码处的解决方案如下所示:

import UIKit

class ViewController: UIViewController {
    
    private let fontSize: CGFloat = 26, margin: CGFloat = 5
    private let numberOfLines: CGFloat = 2

    override func viewDidLoad() {
        super.viewDidLoad()

        setUpNavigation()
    }
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        setMultipleLargeTitle()
    }
    private func setUpNavigation() {
        //Set largeTitle
        navigationItem.largeTitleDisplayMode = .automatic
        navigationController?.navigationBar.prefersLargeTitles = true
        navigationController?.navigationBar.largeTitleTextAttributes = [.font: UIFont.systemFont(ofSize: (fontSize + margin) * numberOfLines)]
        
        //Set title
        title = "multiple large\ntitle is working!"
    }
    private func setMultipleLargeTitle() {
        //Find label
        navigationController?.navigationBar.subviews.forEach({ subview in
            subview.subviews.forEach { subsubview in
                guard let label: UILabel = subsubview as? UILabel else { return }
                //Label settings on direct.
                label.text = title
                label.font = UIFont.systemFont(ofSize: fontSize)
                label.numberOfLines = 0
                label.lineBreakMode = .byWordWrapping
                label.sizeToFit()
            }
        })
    }
}

thank you for reading :)感谢您的阅读:)

You could try:你可以试试:

  1. Create a custom UINavigationController创建自定义UINavigationController
  2. Add the protocol UINavigationBarDelegate to the class definition将协议UINavigationBarDelegate添加到类定义中
  3. Override the function navigationBar(_:shouldPush:)覆盖函数navigationBar(_:shouldPush:)
  4. Activate two lines mode using hidden variable item.setValue(true, forKey: "__largeTitleTwoLineMode")使用隐藏变量item.setValue(true, forKey: "__largeTitleTwoLineMode")激活两行模式
  5. Make navigationController.navigationBar.prefersLargeTitles = true使navigationController.navigationBar.prefersLargeTitles = true

Source - https://bprog.github.io/two-title-nav-bar/来源 - https://bprog.github.io/two-title-nav-bar/

Here you can add a multiline UILabel in the NavigationTitle , You can do it by some kind of customisation in your code and put the UILabel on self.navigationItem.titleView在这里,您可以在NavigationTitle添加多行UILabel ,您可以通过在代码中进行某种自定义并将UILabel放在self.navigationItem.titleView

    let label = UILabel()
    label.backgroundColor = .clear
    label.numberOfLines = 2
    label.font = UIFont(name: "Montserrat-Regular", size: 16.0)!
    label.textAlignment = .center
    label.textColor = .white
    label.text = "FIFA" + " \n " + "Europe 2018-2019"  
    self.navigationItem.titleView = label

Cheers have a good day.祝你有美好的一天。

在此处输入图片说明

To set a multi-line large title in the Navigation Bar, do the following: 要在导航栏中设置多行大标题,请执行以下操作:

Step 1: Add your title to the Navigation Bar via the StoryBoard. 第1步:通过StoryBoard将标题添加到导航栏。

Step 2: Go to your ViewController file and add the following line under viewDidLoad() method 第2步:转到ViewController文件,并在viewDidLoad()方法下添加以下行

self.navigationController?.navigationBar.prefersLargeTitles = true 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM