22

I have this snippet of code used in viewDidLoad of a UIViewController. I'va no errors. Images exists. I get the background but not the image. Image is a sort of logo.

if ([self.navigationController.navigationBar respondsToSelector:@selector(setBackgroundImage:forBarMetrics:)] ) {

    /* Background of navigationBar. */
    UIImage * navigationBarImage = [UIImage imageNamed:@"01_navbar_portrait.png"];
    [self.navigationController.navigationBar setBackgroundImage:navigationBarImage forBarMetrics:UIBarMetricsDefault];

    /* Image in navigationBar */
    UIImage * logoInNavigationBar = [UIImage imageNamed:@"01_logo.png"];
    UIImageView * logoView = [[UIImageView alloc] init];
    [logoView setImage:logoInNavigationBar];
    self.navigationController.navigationItem.titleView = logoView;

}
sensorario
  • 20,262
  • 30
  • 97
  • 159
  • if u put the image(logo) center of nav bar,then wht about u r title? – Hari1251 Mar 04 '13 at 11:12
  • You need to set the navigation item of the view controller that gets pushed onto the navigation stack, not the navigation item of the navigation controller itself. See my answer. – jhabbott Mar 04 '13 at 11:20

7 Answers7

54

The UINavigationController manages the navigation bar by looking at the navigationItem property of the top-most view controller on the navigation stack. So to change the view to a logo, you need to set this up in the view controller that uses the logo (i.e. the root view controller or another one that gets pushed on the stack).

Do something like this in viewDidLoad of your view controller:

UIImage* logoImage = [UIImage imageNamed:@"logo.png"];
self.navigationItem.titleView = [[UIImageView alloc] initWithImage:logoImage];

In your case, you are setting the wrong navigation item:

// Oops...
self.navigationController.navigationItem.titleView = logoView;
// Should be this:
self.navigationItem.titleView = logoView;
jhabbott
  • 18,461
  • 9
  • 58
  • 95
  • 4
    what is the size of UIImage should be for title ?? i tried with 180*40 but it is getting blur. – Krunal Jul 17 '13 at 13:24
  • Long time since OP and answer, but I got hung up on this: `self.navigationItem.titleView = logoView` should be used instead of `self.navigationController.navigationBar.topItem.titleView = logoView` when a new `UIViewController` is being pushed because `topItem` does not reflect the new view controller that was pushed until `viewDidAppear` fires (it still reflects the old view controller in `viewDidLoad` and `viewWillAppear`). – spurgeon Oct 31 '14 at 12:57
  • Anyone knows the frame of the titleView? – Van Du Tran Feb 12 '15 at 00:34
  • 1
    Should use `ScaleAspectFit` – onmyway133 Oct 15 '15 at 07:43
  • In your Xcode preview, open the image. Then click tools -> adjust Size. Open the lock and try to make it around 75 by 75 (pixels). That's the recommended size by apple documentation – Akshansh Thakur Jun 14 '16 at 08:00
  • How to set clips to false to get the view out of bounds? – Takasur Nov 19 '18 at 18:09
9

First we have to create a view which have size as same as navigation bar then add an image view and set set its frame as it looks center in the navigation bar.It works for all ios version and it automatically takes frame size as per device (retina or normal) and works like magic.

UIView *headerView = [[UIView alloc] init];
headerView.frame = CGRectMake(0, 0, 320, 44);

UIImageView *imgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Header.png"]];
imgView.frame = CGRectMake(75, 0, 150, 44);
imgView.contentMode = UIViewContentModeScaleAspectFit;

[headerView addSubview:imgView];

navigationCtrl.navigationBar.topItem.titleView = headerView;

[headerView release];
[imgView release];
AG29
  • 127
  • 1
  • 7
7

Swift:

var logoImage:UIImage = UIImage(named: "logo_text")!
self.navigationItem.titleView = UIImageView(image: logoImage)
Esqarrouth
  • 38,543
  • 21
  • 161
  • 168
4
extension UINavigationController {
func addLogoImage(image: UIImage, navItem: UINavigationItem) {
    let imageView = UIImageView(image: image)
    imageView.contentMode = .scaleAspectFit
    imageView.translatesAutoresizingMaskIntoConstraints = false

    let view = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 44))
    view.addSubview(imageView)

    navItem.titleView = view
    imageView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
    imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    imageView.heightAnchor.constraint(equalTo: view.heightAnchor).isActive = true
    imageView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true

    view.heightAnchor.constraint(equalTo: navigationBar.heightAnchor).isActive = true
    view.centerXAnchor.constraint(equalTo: navigationBar.centerXAnchor).isActive = true
    view.centerYAnchor.constraint(equalTo: navigationBar.centerYAnchor).isActive = true
}
}

Here's what I'm using.

Of course, you might need a bit more constraints, so as to not clash with the right and left bar button items.

Andrew
  • 3,166
  • 21
  • 32
  • 1
    After trying an insane amount of answers, yours finally worked. Thank you! – Geoherna Nov 24 '17 at 07:03
  • This is a better approach using a sharable extension for other places and like @Geoherna I had slight issues with other solutions. I passed in the width & height to the function to make it more extensible for other locations as well. – Nick N Aug 01 '20 at 02:11
2

Perhaps not what you meant, but I ran into this page looking for a way to provide a centered background image for the navigation bar, so in case you're here for that... here's one way.

Stealing a little bit from another answer, you can break your image into foreground and background, then build a new image that stretches the background and centers the foreground, and then set that as your nav bar's background image. Building the image works like so:

// build an image by stretching the bg, then merging it with the fg
CGSize barSize = self.navController.navigationBar.frame.size;
UIImage *fg = [UIImage imageNamed:@"some_fg"];
UIImage *bg = [[UIImage imageNamed:@"some_bg"]
               resizableImageWithCapInsets:UIEdgeInsetsMake(0.f,1.f,0.f,1.f)];
UIGraphicsBeginImageContextWithOptions(barSize, NO, 0.0);
[bg drawInRect:CGRectMake(0, 0, barSize.width, barSize.height)];
[fg drawInRect:CGRectMake((barSize.width-fg.size.width)/2.f,
                          0,
                          fg.size.width,
                          fg.size.height)];
// grab the merged images
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Community
  • 1
  • 1
beOn
  • 1,799
  • 1
  • 12
  • 13
1

You just specify it's frame by

logoView.frame = CGRectMake(initialize frame here);

Then use the following

[self.navigationItem setTitleView:logoView];
manujmv
  • 6,450
  • 1
  • 22
  • 35
  • Your answer is the correct answer, all the others specify `how` to put an image on navigation bar. The question clearly asks `how to center` the image on the navigation bar. Thank you. – oyalhi Jan 06 '16 at 23:23
  • Having said that, I have the following code; however, it still doesn't center the image. Depending on what there is on the left/right side of the navigationBar, the logo centers on the empty space, NOT on the screen. Any pointers? `let image = UIImage(named: "some_logo")!` `let screenWidth = UIScreen.mainScreen().bounds.width` `let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: screenWidth, height: 42))` `imageView.image = image` `imageView.contentMode = .ScaleAspectFit` – oyalhi Jan 06 '16 at 23:28
1
func centeredNavBarImage (){
    let navcontroller = navigationController!
    let image = #imageLiteral(resourceName: "yourImage")
    let imageView = UIImageView(image:image)

    let bannerWidth = navcontroller.navigationItem.accessibilityFrame.size.width
    let bannerHeight = navcontroller.navigationBar.frame.size.height


    let bannerX = bannerWidth / 2 - image.size.width / 2
    let bannerY = bannerHeight / 2 - image.size.height / 2

    imageView.frame = CGRect(x: bannerX, y: bannerY, width: bannerWidth, height: bannerHeight)
    imageView.contentMode = .scaleAspectFit

    navigationItem.titleView = imageView

}

This is a modified code from https://youtu.be/bLkuu_fmlsU

The bannerWidth takes into account a refresh button item I have on the right side of the navbar. Seems to work.

Run the function on ViewDidLoad

Steve B
  • 861
  • 1
  • 7
  • 9