【问题标题】:How to set multi line Large title in navigation bar? ( New feature of iOS 11)如何在导航栏中设置多行大标题? (iOS 11 的新功能)
【发布时间】:2018-06-02 17:38:50
【问题描述】:

我正在其中一个应用程序的导航栏中添加大标题。问题是标题有点长,所以我需要在大标题中添加两行。如何在导航栏中添加两行大标题

这与默认导航栏标题无关!这是关于 iOS 11 中引入的大标题。因此,请确保通过考虑大标题来添加建议。谢谢

【问题讨论】:

  • 在 UIView 中放置标签,将行数设置为 0,然后将视图添加为导航栏的 TitleView。问题解决了
  • @SandeepBhandari 对于不同的导航栏项目,这是否正常(如原始标题标签):后退按钮标签的长度,左/右栏项目?
  • @meaning-matters : 如果 titleView 与左/右栏按钮项重叠,您始终可以指定框架:)
  • 用大标题试试(如果你现在知道的话,iOS 11 的新功能!)
  • @Richie Rich 这不是重复的,请尝试再读一遍描述:)

标签: ios swift uilabel uinavigationbar large-title


【解决方案1】:

基于@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
                })
            }
        }
    }
}

在 UIViewController 中:

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

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

对于大标题的字体和颜色设置:

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

【讨论】:

  • 这很好用。当我尝试这段代码时,我确实注意到动画中有一点差距。可能这里常量57不够用。
  • 是的,我修复它根据设备更改值:让偏移量:CGFloat = UIDevice.current.iPhone5 ? 53 : 57
  • 您是否在 viewdidappear 中看到了一个小故障? @PatricioBravo 先生有什么更好的建议
  • 此解决方案似乎不适用于带有 Xcode 11 的 iOS 13。
  • 似乎在 iOS 13 中,navigationBar 子视图层次结构更加复杂,因此我使用递归函数来更改所有 UILabel。这确实适用于我的标准尺寸标题,但不适用于大标题,虽然......仍在调试这个。
【解决方案2】:

获取导航项子视图并从中找到 UILabel。

试试这个看看:

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

结果如下:

【讨论】:

  • 当我们没有后退按钮时,这工作得很好。你用后退按钮试过了吗?
  • 我同意 Jigar。我有一个后退按钮,这不起作用。当我从左侧稍微滑动页面(好像要返回)但然后让它弹回原位时,它会起作用。
  • 我看到的行为与 JigarThakkar 和 Coltuxumab 相同。 @PatricioBravo 你的建议对我没有帮助。
  • @IliasKarim 将我的代码放在一个新的答案上,希望对您有所帮助
  • 当您导航到标题较小且条形折叠的下一页时,是否有人遇到此问题,当您返回时,您的标题切换回一行,然后是.....
【解决方案3】:

当有后退按钮时,换行解决方案似乎有问题。所以我没有换行,而是让标签自动调整字体。

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

那么就需要在viewDidLayoutSubviews()中调用,保证label可以找到,我们只需要调用一次即可:

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

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

如果有任何navigationController弹出事件返回这个控制器,我们需要在viewDidAppear()中再次调用它。我还没有找到更好的解决方案 - 从流行事件返回时标签字体发生小故障:

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

【讨论】:

    【解决方案4】:

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

    【讨论】:

    • 我必须在哪里添加此代码 请简要介绍一下,以便我可以使用它。谢谢
    • 如果你有按钮,这不起作用,对我来说它只是把第二部分删掉了,它不存在
    • 如果您使用的是 SwiftUI HostingView,这也不起作用。
    【解决方案5】:

    (编辑 7/13:我注意到这个解决方案不支持 scrollView,所以现在我正在研究)

    我在Swift5上找到了一个完美的解决方案

    但对不起我的英语不好,因为我是日本人??学生。

    In case of 2 linesIn case of 3 lines

    首先在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!"
    

    此解决方案最重要的一点是,largeTitleTextAttributes 处的字体大小等于实际字体大小(+边距)乘以行数。

    Description image

    因为,navigationBar 属性的默认规范可能只能显示1 行 largeTitle。

    尽管不知何故,我确实注意到,在直接使用标签设置(导航栏子视图的子视图的标签)的情况下,在导航栏属性的情况下,它可以在 1 行中显示任意数量的行。

    所以,我们应该在导航栏属性中设置大字体,在标签(导航栏的子视图的子视图)中设置小字体,并考虑到边距。

    像这样直接在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()
        }
    })
    

    因此,简而言之,最少代码的解决方案是这样的:

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

    感谢您的阅读:)

    【讨论】:

    • 我无法让它工作,我的标题变大了(因为字体大小)而不是分成多行,您是否缺少一些实现,或者您对滚动视图的调查的任何消息??
    【解决方案6】:

    如果有人在寻找 Title Lable Not Large Title,那么下面的代码就可以了。

    Swift 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 
        }
    

    【讨论】:

    • 这只是在默认标题视图中放置一个多行标签。问题是如何拥有多行 large 标题视图。
    【解决方案7】:

    在这里,您可以在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
    

    【讨论】:

    • @GarySabo 已经过测试,它工作得很好,你可以检查一次属性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-04-14
    • 2018-03-04
    • 1970-01-01
    • 1970-01-01
    • 2018-04-29
    • 2018-03-05
    • 2018-05-18
    相关资源
    最近更新 更多