3
navigationItem.hidesBackButton  = true
navigationItem.leftBarButtonItem = nil

head = UIView()
head.frame = CGRectMake(0, 0, 200, 44)
head.frame.origin.x = CGFloat(0)
navigationItem.titleView = head

I attempt to align the titleView to the left, but it still remains in the middle.

tktsubota
  • 9,371
  • 3
  • 32
  • 40
TIMEX
  • 259,804
  • 351
  • 777
  • 1,080

10 Answers10

14

Try this:

let title = UILabel()
title.text = "TITLE"

let spacer = UIView()
let constraint = spacer.widthAnchor.constraint(greaterThanOrEqualToConstant: CGFloat.greatestFiniteMagnitude)
constraint.isActive = true
constraint.priority = .defaultLow

let stack = UIStackView(arrangedSubviews: [title, spacer])
stack.axis = .horizontal

navigationItem.titleView = stack

The idea is that main view (in this case title) will take all the space it needs and spacer view will take all the free space left.

enter image description here

Murlakatam
  • 2,729
  • 2
  • 26
  • 20
  • 1
    Thanks for the answer but Xcode gives me a warning `_NSLayoutConstraintNumberExceedsLimit` because of `CGFloat.greatestFiniteMagnitude` is it possible to solve it ? – atalayasa Jul 24 '20 at 07:31
  • 1
    You can either use some hardcoded value, or something like this: `max(UIScreen.main.bounds.width, UIScreen.main.bounds.height)` – Murlakatam Jul 26 '20 at 14:39
  • This breaks on iOS 16.0 but works on iOS 16.1. – Patrick Jan 25 '23 at 05:27
6

I figured it out.

I just need to set my custom UIView as the leftBarButtonItem.

TIMEX
  • 259,804
  • 351
  • 777
  • 1,080
4

I had a similar requirement of adding the Title along with the subtitle to the left of the navbar. I couldn't achieve it with a TitleView since it cannot be aligned left. So I took @TIMEZ and @Wain's answers, along with responses from the thread here and added a complete answer, in case it helps anyone :

let titleLabel = UILabel()
    titleLabel.text = "Pillars"
    titleLabel.textAlignment = .center
    titleLabel.font = .preferredFont(forTextStyle: UIFont.TextStyle.headline)

    let subtitleLabel = UILabel()
    subtitleLabel.text = "How did you do today?"
    subtitleLabel.textAlignment = .center
    subtitleLabel.font = .preferredFont(forTextStyle: UIFont.TextStyle.subheadline)

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

    let customTitles = UIBarButtonItem.init(customView: stackView)
    self.navigationItem.leftBarButtonItems = [customTitles]
Kavisha
  • 155
  • 1
  • 10
3

If it's a custom UIView, override intrinsicContentSize and return

CGSize(width: .greatestFiniteMagnitude, height: UIView.noIntrinsicMetric)

This will stretch the view to the entire width between left and right bar button items.

2

You can't align a title view to the left. You can create a title view and add a subview positioned to its left. If you're looking to display in place of the back button then you should be using a bar button item instead of title view.

Wain
  • 118,658
  • 15
  • 128
  • 151
1

I don't think Apple wants you to do that. Navigation bars have a pretty specific purpose that often involves having something else in the top left corner like a Back button. You might be better off making a custom UIView or UIToolbar that looks like the navigation bar.

yesthisisjoe
  • 1,987
  • 2
  • 16
  • 32
0

You can constraint the titleView to the navigationBars leftAnchor.

 private func setupNavigationBarTitleView() {
        let titleView = YourCustomTitleView()
        navigationBarTitleView = titleView
        navigationBarTitleView?.translatesAutoresizingMaskIntoConstraints = false
        navigationItem.titleView = navigationBarTitleView

        if let navigationBar = navigationController?.navigationBar {
            NSLayoutConstraint.activate([
                titleView.leadingAnchor.constraint(equalTo: navigationBar.leadingAnchor, constant: 16),
                titleView.heightAnchor.constraint(equalToConstant: 36)
            ])
        }

    }
Sebastian Boldt
  • 5,283
  • 9
  • 52
  • 64
0

The simplest solution is to add low priority constraint for title width.

    let titleLabel = UILabel()
    titleLabel.textAlignment = .left

    ...

    let c = titleLabe.widthAnchor.constraint(equalToConstant: 10000)
    c.priority = .required - 1
    c.isActive = true

    navigationItem.titleView = titleLabel
malex
  • 9,874
  • 3
  • 56
  • 77
0

Hey guys after trying most of the solutions above. I found that most of em still did not meet my prod requirements. Here is a solution I came up with after trying out different solutions.

func setLeftAlignTitleView(font: UIFont, text: String, textColor: UIColor) {
    guard let navFrame = navigationController?.navigationBar.frame else{
        return
    }
    
    let parentView = UIView(frame: CGRect(x: 0, y: 0, width: navFrame.width*3, height: navFrame.height))
    self.navigationItem.titleView = parentView
    
    let label = UILabel(frame: .init(x: parentView.frame.minX, y: parentView.frame.minY, width: parentView.frame.width, height: parentView.frame.height))
    label.backgroundColor = .clear
    label.numberOfLines = 2
    label.font = font
    label.textAlignment = .left
    label.textColor = textColor
    label.text = text
    
    parentView.addSubview(label)
}
ouflak
  • 2,458
  • 10
  • 44
  • 49
0
let navLabel = UILabel(frame: CGRect(x: 0, y: 0, width: view.frame.width - 32, height: view.frame.height))
    navLabel.text = "Hi, \(CurrentUser.firstName)"
    navLabel.textColor = UIColor.white
    navLabel.font = UIFont.systemFont(ofSize: 20)
    navigationItem.titleView = navLabel
Timchang Wuyep
  • 629
  • 7
  • 10