Make NavigationBar's titleView larger than itself
I found why you got this issue. It's because of a private view which has name _UINavigationBarContentView
. It's a subview of UINavigationBar
. navigationItem.titleView
is contained in this view.
At first time, when you change navigationItem.titleView
. _UINavigationBarContentView.clipsToBounds
is false
.But after you push another controller and pop back, _UINavigationBarContentView.clipsToBounds
is true
. That's why titleView
is cropped.
So i have a temporary solution. Each time when viewController
appears, find this view and change _UINavigationBarContentView.clipsToBounds
to false
and layout titleView
.
override func viewDidAppear(_ animated: Bool) {
for view : UIView in (navigationController?.navigationBar.subviews)! {
view.clipsToBounds = false;
}
navigationItem.titleView?.layoutIfNeeded()
}
override func viewWillAppear(_ animated: Bool) {
for view : UIView in (navigationController?.navigationBar.subviews)! {
view.clipsToBounds = false;
}
navigationItem.titleView?.layoutIfNeeded()
}
I tried and it works. But i think you shouldn't do something whit it because it's private view. Maybe Apple don't want us do anything with it.
Hope somehow my suggestion can help you. Good luck ;)
SOLUTION
Adding observer for _UINavigationBarContentView.clipsToBounds
, each time when it changes to false
, set to true
and update layout of titleView
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let logo = UIImage(named: "Logo")
let titleView = UIView(frame: CGRect(x: 0, y: 0, width: 60, height: 60))
let imageView = UIImageView(image: logo)
imageView.frame = CGRect(x: 0, y: 0, width: titleView.frame.width, height: titleView.frame.height)
titleView.addSubview(imageView)
imageView.contentMode = .scaleAspectFit
imageView.image = logo
navigationItem.titleView = titleView
navigationController?.navigationBar.subviews[2].addObserver(self, forKeyPath: "clipsToBounds", options: [.old, .new], context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if (navigationController?.navigationBar.subviews[2].isEqual(object))! {
DispatchQueue.main.async {
self.navigationController?.navigationBar.subviews[2].clipsToBounds = false
self.navigationItem.titleView?.layoutIfNeeded()
}
}
}
deinit {
navigationController?.navigationBar.subviews[2].removeObserver(self, forKeyPath: "clipsToBounds")
}
For more detail and easier, you can check my demo here https://github.com/trungducc/stackoverflow/tree/big-title-navigation-bar
Controlling size / position of UINavigationItem titleView
Instead of using your image view as the title view, create another view that contains the image view. Set that view as the title view of the navigation item; now you’re free to adjust the image view’s frame within the title view.
Adjusting navigationItem.titleView's frame?
Sometime in between your view controller's viewWillAppear: & viewDidAppear:, the navigation bar is repositioning your titleView and resizing it to fit if necessary. It can end up uncentered because the navigation bar is prefering not to resize your titleView to fit between the buttons. It seems to try to center the title view if it's small enough, but if not will move your titleView off-center, and then I think only as last resort will resize. The effect is that the titleView is taking up all the space between the two buttons, if its textAlignment is centered then it will centered in that space though not the centered with respect to the whole screen. You can see this in your screen shot.
One answer is to make your titleView narrower so the navigation bar can center it, so try about 160 instead of 180 when you set your titleView.frame. It sucks that, when creating the view programmatically like you are, one has to put an estimate for that width into the code. What would be good is a way to maximize that space while staying centered.
It's possible to start with the titleView being the screen width, then after the navigation bar changes titleView.frame, update it again yourself in the view controller's viewDidAppear:. Using its adjusted titleView.frame.origin.x and size.width along with the screen width, you can calculate the largest of the left & right margins, then set the origin.x to that, the size.width to the screen width minus that times 2. However that doesn't take effect until after the pushed view has animated in and the shift afterwards is visible. You could hide the titleView in viewWillAppear: then unhide in viewDidAppear: after centering it, so instead of sliding in with an off-center titleView which is then shifted, it would slide in with no title which then appears.
A better possibility is to make your titleView your own subclass of UIView (or UILabel or whichever) and override setFrame to resize itself to stay centered in its superview. If I ever end up doing this myself I'll post it here. Or maybe someone else knows another place to change the titleView's frame after its been updated but before the view slides in without a view subclass.
How can I get a full-sized UINavigationBar titleView
Setting the titleView of your view's navigationItem will never do the trick. Instead, you can add a subView to the navigation controller's navigationBar :
UIView* ctrl = [[UIView alloc] initWithFrame:navController.navigationBar.bounds];
ctrl.backgroundColor = [UIColor yellowColor];
ctrl.autoresizingMask = UIViewAutoresizingFlexibleWidth;
[navController.navigationBar addSubview:ctrl];
How to resize Title in a navigation bar dynamically
Used the below code in ViewDidload .
Objective C
self.title = @"Your TiTle Text";
UILabel* tlabel=[[UILabel alloc] initWithFrame:CGRectMake(0,0, 200, 40)];
tlabel.text=self.navigationItem.title;
tlabel.textColor=[UIColor whiteColor];
tlabel.font = [UIFont fontWithName:@"Helvetica-Bold" size: 30.0];
tlabel.backgroundColor =[UIColor clearColor];
tlabel.adjustsFontSizeToFitWidth=YES;
tlabel.textAlignment = NSTextAlignmentCenter;
self.navigationItem.titleView=tlabel;
Swift Version
self.title = "Your Title Text"
let tlabel = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 40))
tlabel.text = self.title
tlabel.textColor = UIColor.white
tlabel.font = UIFont.systemFont(ofSize: 30, weight: .bold)
tlabel.backgroundColor = UIColor.clear
tlabel.adjustsFontSizeToFitWidth = true
tlabel.textAlignment = .center
self.navigationItem.titleView = tlabel
Hope it works for you.Thanks
Related Topics
The Bundle's Info.Plist Does Not Contain a Cfbundleversion Key or Its Value Is Not a String
Libz.Dylib Versus Libz.1.2.3.Dylib Versus Libz.1.2.5.Dylib
Programmatically Highlight Uibarbuttonitem
Simple Uitableview in Swift - Unexpectedly Found Nil
What Is the Swift Preprocessor Equivalent to iOS Version Check Comparison
Adding Swift Files to Test Target Not Fixing Unit Tests
Core Data Predicate:Unimplemented SQL Generation for Predicate
iOS Swift 3:Convert "Yyyy-Mm-Dd'T'Hh:Mm:Ssz" Format String to Date Object
Calling Instance Method During Initialization in Swift
iOS Client Certificates and Mobile Device Management
Using Sysctlbyname() from Swift
Apple MACh-O Linker (Id) Warning:Building for MACosx, But Linking Against Dylib Built for iOS
Google Maps Sdk Not Displaying Properly in Uiview
How to Launch an App in Foreground When I Enter an Ibeacon Range