Why is custom navigation bar button image stretched?
Asked Answered
U

4

8

I tried to add a navigation bar button with custom image. However, whatever method I use, the image always appears stretched.

Method 1:

    let barbuttonitem = UIBarButtonItem(image: UIImage(named: "apps_small"), style: .plain, target: self, action: nil)
    navigationItem.leftBarButtonItem = barbuttonitem

It appears like this:

Method 1

Method 2:

    let button = UIButton(type: .custom)
    button.setImage(UIImage(named: "apps_small"), for: .normal)
    button.addTarget(self, action: #selector(TeachingRootViewController.appsTouched), for: .touchUpInside)
    button.frame = CGRect(x: 0, y: 0, width: 10, height: 10)
    button.bounds = CGRect(x: 0, y: 0, width: 10, height: 10)
    navigationItem.leftBarButtonItem = UIBarButtonItem(customView: button)

It appears like this:

Method 2

Method 3:

    let button = UIButton(type: .custom)
    button.setImage(UIImage(named: "apps_small"), for: .normal)
    button.setTitle("Button", for: .normal)
    button.frame = CGRect(x: 0, y: 0, width: 10, height: 10)
    button.bounds = CGRect(x: 0, y: 0, width: 10, height: 10)
    button.imageEdgeInsets = .init(top: 5, left: 5, bottom: 5, right: 300)
    navigationItem.leftBarButtonItem = UIBarButtonItem(customView: button)
    navigationItem.leftBarButtonItem?.imageInsets = .init(top: 5, left: 5, bottom: 5, right: 300)

It looks like this:

Method 3

As you can see the title is gone.

In the UI Hierarchy, it looks like this:

UI Hierarchy

It appears that the button has taken up all spaces in the navigation bar.

However, there is no problem for button with a system item:

System item

Is there anybody who knows the reason for this problem? I think I have run out of ideas.

Unbolt answered 4/8, 2017 at 21:5 Comment(1)
did you fix this?Selfconfidence
D
8

The above answer is a workaround and not a proper fix. The correct answer is you should have generate your photos with the correct sizes

  • asset@1x: 22x22px
  • asset@2x: 44x44px
  • asset@3x: 66x66px
Dieter answered 11/5, 2018 at 12:25 Comment(0)
S
3

Try adding it as a subView instead of setting it as the leftBarButtonItem

var leftButton = UIButton(frame:CGRect(x: 0, y: 0, width: 10, height: 10))
var background = UIImageView(image: UIImage(named: "apps_small"))
background.frame = CGRect(x: 0, y: 0, width: 10, height: 10)
leftButton.addSubview(background)
self.navigationController.navigationBar.addSubview(leftButton)
Selfconfidence answered 4/8, 2017 at 21:20 Comment(4)
Thanks for reply! However it won't compile... The compiler complains that "Value of type 'UINavigationItem' has no member 'addSubview'". UIBarButtonItem also doesn't have 'addSubview'.Unbolt
I am not creating a UIBarButtonItem .. ill edit this to use the navController.. so you can try againSelfconfidence
@Unbolt can you try again with a UIButton and a UINavigationBar as the code I provided?Selfconfidence
Okay... It works... Although this solution looks a little strange to me... I'm still wondering why is my previous method corrupt...Unbolt
C
3

As per my experience, You have faced this issue because you're added large size images for all resolution 1X, 2X and 3X. You need to scale it down to a size more appropriate for the navigation bar.

Solution: 1

You need to scale it down to a size more appropriate for the navigation bar. Please have look image sizes for UINavigationBar

asset@1X Size: 24X24

asset@2X Size: 48X48

asset@3X Size: 72X72

Solution: 2

If you want to go with the same images then you need to do below changes in your code.

You just need to add UIImageView inside the UIView then everything works as expected.

Code:

    let containerView = UIControl(frame: CGRect.init(x: 0, y: 0, width: 30, height: 30))
    containerView.addTarget(self, action: #selector(handleSearch), for: .touchUpInside)
    let imageSearch = UIImageView(frame: CGRect.init(x: 0, y: 0, width: 30, height: 30))
    imageSearch.image = UIImage(named: "search")
    containerView.addSubview(imageSearch)                
    let searchBarButtonItem = UIBarButtonItem(customView: containerView)
    navigationItem.rightBarButtonItem = searchBarButtonItem
Colas answered 21/4, 2020 at 12:35 Comment(0)
A
0

It's all about the Image size that you put inside your UIButton.

If you are using UIButton as a custom view for

UIBarButtonItem(customView: button)

and inside that custom button, you are setting an image. It is better to set the image size to something you need.

let button = UIButton(type: .custom)
button.setImage(UIImage(named: "image")!.resizeImage(newWidth: 25), for: .normal)

And this is a good extension for resizing images in your app. it is using CoreGraphic to resize.

extension UIImage{
    //Resize image
    func resizeImage(newWidth: CGFloat) -> UIImage {
        let originalImage = self
        
        let scale = newWidth / self.size.width
        let newHeight = self.size.height * scale
        
        let newImage = self.resizeWithCoreGraphics(to: CGSize(width: newWidth, height: newHeight)) ?? originalImage
        
        return newImage
    }
    
    private func resizeWithCoreGraphics(to newSize: CGSize) -> UIImage? {
        guard let cgImage = cgImage, let colorSpace = cgImage.colorSpace else { return nil }
        
        let width = Int(newSize.width)
        let height = Int(newSize.height)
        let bitsPerComponent = cgImage.bitsPerComponent
        let bytesPerRow = cgImage.bytesPerRow
        let bitmapInfo = cgImage.bitmapInfo
        
        guard let context = CGContext(data: nil, width: width, height: height,
                                      bitsPerComponent: bitsPerComponent,
                                      bytesPerRow: bytesPerRow, space: colorSpace,
                                      bitmapInfo: bitmapInfo.rawValue) else { return nil }
        context.interpolationQuality = .high
        let rect = CGRect(origin: CGPoint.zero, size: newSize)
        context.draw(cgImage, in: rect)
        
        return context.makeImage().flatMap { UIImage(cgImage: $0) }
    }
}
Assumption answered 6/9, 2022 at 11:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.