iOS - 在导航栏的标题中添加图像和文本

iOS - add image and text in title of Navigation bar

我想创建一个类似于所附图片中的导航栏。

导航栏的标题将是图像和文本的组合。

  1. 是否应该根据任何最佳实践来完成此操作?

  2. 怎么做到的

作为 this answer shows,最简单的解决方案是将文本添加到您的图像并将该图像添加到导航栏,如下所示:

var image = UIImage(named: "logo.png")
self.navigationItem.titleView = UIImageView(image: image)

但是如果您必须分别添加文本和图像(例如,在本地化的情况下),您可以将导航栏的标题视图设置为同时包含图像和文本,方法是将它们添加到 UIView 并将 navigationItem 的标题视图设置为 UIView,例如(假设导航栏是导航控制器的一部分):

// Only execute the code if there's a navigation controller 
if self.navigationController == nil {
    return
}

// Create a navView to add to the navigation bar
let navView = UIView()

// Create the label
let label = UILabel()
label.text = "Text"
label.sizeToFit()
label.center = navView.center
label.textAlignment = NSTextAlignment.Center

// Create the image view
let image = UIImageView()
image.image = UIImage(named: "Image.png")
// To maintain the image's aspect ratio:
let imageAspect = image.image!.size.width/image.image!.size.height
// Setting the image frame so that it's immediately before the text:
image.frame = CGRect(x: label.frame.origin.x-label.frame.size.height*imageAspect, y: label.frame.origin.y, width: label.frame.size.height*imageAspect, height: label.frame.size.height)
image.contentMode = UIViewContentMode.ScaleAspectFit

// Add both the label and image view to the navView
navView.addSubview(label)
navView.addSubview(image)

// Set the navigation bar's navigation item's titleView to the navView
self.navigationItem.titleView = navView

// Set the navView's frame to fit within the titleView
navView.sizeToFit()

这是我给 Swift 4 的 2 美分,因为接受的答案对我不起作用(大部分都在屏幕外):

// .. in ViewController
var navBar = CustomTitleView()

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)


    // =================== navBar =====================
    navBar.loadWith(title: "Budget Overview", leftImage: Images.pie_chart)
    self.navigationItem.titleView = navBar

}

class CustomTitleView: UIView
{

var title_label = CustomLabel()
var left_imageView = UIImageView()

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

required init?(coder aDecoder: NSCoder){
    super.init(coder: aDecoder)
    setup()
}

func setup(){
    self.addSubview(title_label)
    self.addSubview(left_imageView)

}

func loadWith(title: String, leftImage: UIImage?)
{

    //self.backgroundColor = .yellow

    // =================== title_label ==================
    //title_label.backgroundColor = .blue
    title_label.text = title
    title_label.font = UIFont.systemFont(ofSize: FontManager.fontSize + 5)


    // =================== imageView ===================
    left_imageView.image = leftImage

    setupFrames()
}

func setupFrames()
{

    let height: CGFloat = Navigation.topViewController()?.navigationController?.navigationBar.frame.height ?? 44
    let image_size: CGFloat = height * 0.8

    left_imageView.frame = CGRect(x: 0,
                                  y: (height - image_size) / 2,
                                  width: (left_imageView.image == nil) ? 0 : image_size,
                                  height: image_size)

    let titleWidth: CGFloat = title_label.intrinsicContentSize.width + 10
    title_label.frame = CGRect(x: left_imageView.frame.maxX + 5,
                               y: 0,
                               width: titleWidth,
                               height: height)



    contentWidth = Int(left_imageView.frame.width)
    self.frame = CGRect(x: 0, y: 0, width: CGFloat(contentWidth), height: height)
}


var contentWidth: Int = 0 //if its CGFloat, it infinitely calls layoutSubviews(), changing franction of a width 
override func layoutSubviews() {
    super.layoutSubviews()

    self.frame.size.width = CGFloat(contentWidth)

}

}

// 为我工作

  1. 创建视图并设置框架
  2. 现在在视图中添加图像并设置框架
  3. 添加图片后,在同一视图中添加标签并设置边框
  4. 将图像和标签添加到视图后,将相同的视图添加到 navigationItem

    let navigationView = UIView(frame: CGRect(x: 0, y: 0, width: 50 , height: 55))

    let labell : UILabel = UILabel(frame: CGRect(x: -38, y: 25, width: 150, height: 25))
    labell.text = "Your text"
    labell.textColor = UIColor.black
    labell.font = UIFont.boldSystemFont(ofSize: 10)
    navigationView.addSubview(labell)
    
    let image : UIImage = UIImage(named: ValidationMessage.headerLogoName)!
    let imageView = UIImageView(frame: CGRect(x: -20, y: 0, width: 100, height: 30))
    imageView.contentMode = .scaleAspectFit
    imageView.image = image
    //navigationItem.titleView = imageView
    
    navigationView.addSubview(imageView)
    
    navigationItem.titleView = navigationView
    

水平使用UIStackView 应该更干净、更容易

请将下一个扩展添加到 UIViewController

extension UIViewController {
    func setTitle(_ title: String, andImage image: UIImage) {
        let titleLbl = UILabel()
        titleLbl.text = title
        titleLbl.textColor = UIColor.white
        titleLbl.font = UIFont.systemFont(ofSize: 20.0, weight: .bold)
        let imageView = UIImageView(image: image)
        let titleView = UIStackView(arrangedSubviews: [imageView, titleLbl])
        titleView.axis = .horizontal
        titleView.spacing = 10.0
        navigationItem.titleView = titleView
    }
}

然后在你的 viewController:

中使用它
setTitle("yourTitle", andImage: UIImage(named: "yourImage"))

(这会将文本和图标一起居中对齐,如果您希望文本居中而图标在左侧,只需添加一个空的 UIView ,宽度约束等于图标宽度)

Swift 4.2 + Interface Builder 解决方案

作为 follow-on 到 Lyndsey Scott's answer,您还可以在 Interface Builder 中创建一个 UIView .xib,使用它来布置您的标题和图像,然后更新它 on-the-fly 通过 @IBOutlet。这对于动态内容、国际化、可维护性等很有用。

创建一个带有 UILabel 出口的 UIView subclass 并将新的 .xib 分配给此 class:

import UIKit

class FolderTitleView: UIView {

    @IBOutlet weak var title : UILabel!

    /// Create an instance of the class from its .xib
    class func instanceFromNib() -> FolderTitleView {
        return UINib(nibName: "FolderTitleView", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! FolderTitleView
    }
}

在你的 .xib 中将标签连接到你的插座(title 在我的例子中),然后在你的 UIViewController:

/// Reference to the title view
var folderTitleView : FolderTitleView?

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    // Set the screen title to match the active folder
    updateTitle()    
}

/// Updates the title of the navigation controller.
func updateTitle() {
    self.title = ""
    if folderTitleView == nil {
        folderTitleView = FolderTitleView.instanceFromNib()
        self.navigationItem.titleView = folderTitleView
    }
    folderTitleView!.title.text = "Listening"
    folderTitleView!.layoutIfNeeded()
}

这会产生一个漂亮的 self-centering 标题栏,其中包含您可以通过代码轻松更新的嵌入图像。