I noticed that the titleView\'s position depends on the rightbarbutton title. How can I set the frame of the titleView to be in the center instead?
I\'ve tried setting
After setting up your titleView or titleLabel, call sizeToFit
on it, also make sure titleLabel.textAlignment = UITextAlignmentCenter
. It'll be centered in the width of the navbar rather than in the space between the button edge and far edge of navbar.
Override intrinsicContentSize
in your custom view:
- (CGSize )intrinsicContentSize {
return CGSizeMake(180, 44);
}
None of the suggestions here really worked for me. My issue was that I was setting titleView while the navigation bar was in the middle of it's transition - I'd get this weird jitter where the titleView would flicker over to the left, and then end up back in the center.
I ended up following smallduck's idea and overriding setFrame, was as simple as:
- (void)setFrame:(CGRect)frame {
[super setFrame:CGRectMake(0, 0, self.superview.bounds.size.width, self.superview.bounds.size.height)];
}
-(void) awakeFromNib
{
UIButton *titleLabel = [UIButton buttonWithType:UIButtonTypeCustom];
[titleLabel setTitle:@"Right Eye" forState:UIControlStateNormal];
[titleLabel setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[titleLabel setTitleColor:[UIColor blackColor] forState:UIControlStateHighlighted];
titleLabel.titleLabel.backgroundColor = [UIColor clearColor];
titleLabel.titleLabel.font = [UIFont boldSystemFontOfSize:20.0];
titleLabel.titleLabel.shadowColor = [UIColor colorWithWhite:0.0 alpha:0.3];
[titleLabel addTarget:self action:@selector(titleTap:) forControlEvents:UIControlEventTouchUpInside];
titleLabel.frame = CGRectMake(0, 0, 400, 20);
self.navigationItem.titleView = titleLabel;
}
I was implementing a two row title similar to something WhatsApp is doing (title and subtitle).
I fixed this problem by subclassing UINavigationController
and overriding viewDidLayoutSubviews()
.
My titleView looks like the following (in a viewController
):
let frame = self.navigationController?.navigationBar.bounds ?? CGRect.zero
// This is a container view for the two labels, laying them out vertically
let titleView = UIStackView(arrangedSubviews: [self._titleLabel, self._promptLabel])
titleView.axis = .vertical
titleView.alignment = .center
titleView.distribution = .fill
titleView.frame = frame // set the frame to the navbarFrame initially
titleView.spacing = 0
// The wrapper is necessary for laying out the stackView as the titleView
let wrapperView = UIView(frame: frame)
wrapperView.addSubview(titleView)
self.navigationItem.titleView = wrapperView
My viewDidLayoutSubviews()
:
guard let navigationItem = self.topViewController?.navigationItem,
let titleView = navigationItem.titleView,
let wrapperView = titleView.subviews[0] as? UIStackView else { return }
var width : CGFloat = 0
for view in wrapperView.arrangedSubviews {
view.sizeToFit()
width = max(width, view.frame.size.width)
}
titleView.frame.size.width = width
titleView.frame.size.height = self.navigationBar.frame.height
wrapperView.frame = titleView.bounds
wrapperView.center.x = self.navigationBar.convert(self.navigationBar.center, to: titleView).x
wrapperView.center.y = titleView.frame.height / 2
self.navigationBar.layoutIfNeeded()
Note: The trick is to have a wrapper view around your titleView which can be layed out by the navigation bar. Then adjust the frame of your titleView to what you desire.
I have a slightly other use case (vertical offset of UIButton as titleView on iOS 7). After a long time I came up with using the contentEdgeInsets
property of the UIButton to shift the content in its frame.