Search code examples
iosswiftuinavigationbarimagebutton

Unable to add image (profile picture) button to UINavigationBar


I'm trying to get my UINavigationBar to display a circular profile picture in the upper left. I can make it display images/icons with ease using the following instantiation.

self.navigationItem.leftBarButtonItem = UIBarButtonItem(image: icon, style: .plain, target: self, action: #selector(funcToCall))

The issue is that when trying to work with profile pictures, neither custom views, not image instantiation produce the desired result.

Attempt 1 -- Swift 4 (Image Instantiation)

let img = originalImage.withRenderingMode(.alwaysOriginal)
self.navigationItem.leftBarButtonItem = UIBarButtonItem(image: img, style: .plain, target: self, action: #selector(goToProfile))

This attempt produces the following result.

Problems:

  • Even though I specified leftBarButtonItem, it is showing up in the middle
  • I can't produce a circular button using this strategy as there is no view to change the cornerRadius for.

Attempt 2 -- Swift 4 (Custom Views)

let idealButton = UIButton(frame: CGRect(x: 0, y: 0, width: 32, height: 32))
idealButton.setImage(imgToUse, for: .normal)
idealButton.imageView?.contentMode = .scaleAspectFill

idealButton.imageView?.layer.cornerRadius = 0.5 * idealButton.frame.width
idealButton.imageView?.layer.borderWidth = 0.75
idealButton.imageView?.layer.borderColor = rgba(240,240,240,1).cgColor

idealButton.addTarget(self, action: #selector(goToProfile), for: .touchUpInside)
navigationItem.setLeftBarButton(UIBarButtonItem(customView: idealButton), animated: false)

This attempt produces the following result.

Problems

  • The image spans the entire UINavigationBar. It is not constrained to the dimensions specified.

Any help is much appreciated. Thanks!


Solution

  • Let's try it with UIButton added as subview of UINavigationBar

    So start with creating button and setting its properties (you can use lazy variable in global scope)

    lazy var idealButton: UIButton = {
        let button = UIButton()
        button.setImage(imgToUse, for: .normal)
        button.imageView?.layer.cornerRadius = 16
        ... // set other button's properties (border, target, colors, etc.)
        return button
    }()
    

    now add this button as subview of current navigationController's navigationBar

    guard let navigationBar = navigationController?.navigationBar else { return }
    navigationBar.addSubview(idealButton)
    

    then just set constraints for your button (you need to set height and width as you need and left and bottom constraints equal to navigationBar's constraints)

    idealButton.translatesAutoresizingMaskIntoConstraints = false
    
    NSLayoutConstraint.activate([
        idealButton.leftAnchor.constraint(equalTo: navigationBar.leftAnchor, constant: 20),
        idealButton.bottomAnchor.constraint(equalTo: navigationBar.bottomAnchor, constant: -6),
        idealButton.heightAnchor.constraint(equalToConstant: 32),
        idealButton.widthAnchor.constraint(equalToConstant: 32)
    ])