iOS is doing this because the frame you initialize is alway 300+width pixels. It is trying to center the full frame, the frame is larger than the space it wants to fit it in (because of the button) and therefore your label gets pushed to the right.
What you need to do is give the Frame of the navLabel the minimum size it needs.
So if your text is only 100px wide, but the frame is 400px, then iOS is trying to center the 400px inside the Navigation header, and doesn't have enough space. When you set the size to the actual 100px that is needed, iOS will center your header correctly, because there is plenty of space to center 100px.
The code snippet below should help you to detect the minimum size your frame needs, depending on the font and the text you try to put in.
Make sure the frame of the label is as small as possible, but does not exceed the max width.
(the width of the navigation bar).
UIFont* titleFont = [UIFont fontWithName:@"Helvetica" size:30];
CGSize requestedTitleSize = [titleText sizeWithAttributes:@{NSFontAttributeName: titleFont}];
CGFloat titleWidth = MIN(maxTitleWidth, requestedTitleSize.width);
UILabel *navLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, titleWidth, 20)];
navLabel.backgroundColor = [UIColor whiteColor];
navLabel.textColor = [UIColor redColor];
navLabel.font = [UIFont fontWithName:@"Helvetica" size:30];
navLabel.textAlignment = NSTextAlignmentCenter;
navLabel.text = titleText;
self.navigationItem.titleView = navLabel;
Swift 5.0
let titleFont = UIFont.systemFont(ofSize: 17.0)
let title = "My Title"
let titleSize = title.size(withAttributes: [.font: titleFont])
let frame = CGRect(x: 0, y: 0, width: titleSize.width, height: 20.0)
let titleLabel = UILabel(frame: frame)
titleLabel.font = titleFont
titleLabel.textColor = .red
titleLabel.textAlignment = .center
titleLabel.text = title
navigationItem.titleView = titleLabel
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…