navigation bar rightbaritem image-button bug iOS 11
Solution 1
Reason
The problem appears because from ios 11 UIBarButtonItem
uses autolayout instead of dealing with frames.
Solution
You should add width constraint for this image-button if you use Xcode 9.
button.widthAnchor.constraint(equalToConstant: 32.0).isActive = true
button.heightAnchor.constraint(equalToConstant: 32.0).isActive = true
PS
button
is not UIBarButtonItem
, it is UIButton
inside UIBarButtonItem
. You should set constraint not for UIBarButtonItem
, but for elements inside it.
Solution 2
Thanks all for contributing! you guys are right!. for xcode9 ios11 you need to put a constraint.
let widthConstraint = button.widthAnchor.constraint(equalToConstant: 32)
let heightConstraint = button.heightAnchor.constraint(equalToConstant: 32)
heightConstraint.isActive = true
widthConstraint.isActive = true
Solution 3
Well, The new barButtonItem
uses autolayout instead of dealing with frames.
The image you were adding to the button is larger than the button size itself. That's why the button itself got stretched to the image's size. You have to resize the image to match the needed button's size, before adding it to the button.
Solution 4
Objective C code is obsolete now. But for the user who has to build/maintain Objective C projects in iOS 11 has following translation from Swift ( Karoly Nyisztor answer ) to Objective C helpful.
// UIView+Navbar.h
#import <UIKit/UIKit.h>
@interface UIView (Navbar)
- (void)applyNavBarConstraints:(CGFloat)width height:(CGFloat)height;
@end
//----------
// UIView+Navbar.m
#import "UIView+Navbar.h"
@implementation UIView (Navbar)
- (void)applyNavBarConstraints:(CGFloat)width height:(CGFloat)height
{
if (width == 0 || height == 0) {
return;
}
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:height];
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:width];
[heightConstraint setActive:TRUE];
[widthConstraint setActive:TRUE];
}
//----------
// Usage :-
[button applyNavBarConstraints:33 height:33];
Solution 5
I wrote a tiny extension for setting the constraints on navbar items:
import UIKit
extension UIView {
func applyNavBarConstraints(size: (width: CGFloat, height: CGFloat)) {
let widthConstraint = self.widthAnchor.constraint(equalToConstant: size.width)
let heightConstraint = self.heightAnchor.constraint(equalToConstant: size.height)
heightConstraint.isActive = true
widthConstraint.isActive = true
}
}
// Usage
button.applyNavBarConstraints(size: (width: 33, height: 33))
Related videos on Youtube
lorenzo gonzalez
Updated on September 18, 2020Comments
-
lorenzo gonzalez almost 4 years
This code works ok in ios10. i get my label and an image button which is the user photo profile, circular round.. ok. but when running xcode 9 ios11 simulator i get it streched out. the button frame has to be 32x32 , when checking on the sim and getting the view and telling xcode to describe the view i get output as 170x32 or somethint like that.
heres my code.
let labelbutton = UIButton( type: .system) labelbutton.addTarget(self, action:#selector(self.toLogin(_:)), for: .touchUpInside) labelbutton.setTitleColor(UIColor.white, for: .normal) labelbutton.contentHorizontalAlignment = .right labelbutton.titleLabel?.font = UIFont.systemFont(ofSize: 18.00) let button = UIButton(type: .custom) button.addTarget(self, action:#selector(self.toLogin(_:)), for: .touchUpInside) button.frame = CGRect(x: 0, y: 0, width: 32, height: 32) button.setTitleColor(UIColor.white, for: .normal) button.setTitleColor(UIColor.white, for: .highlighted) var buttomItem : UIBarButtonItem = UIBarButtonItem() buttomItem.customView = button buttomItem.target = self buttomItem.action = "ToLogin" var labelItem : UIBarButtonItem = UIBarButtonItem() labelItem.customView = labelbutton labelItem.target = self labelItem.action = "ToLogin" if let user = PFUser.current() { print("LOGIN : checkiando si existe usuario ") labelbutton.setTitle(USERNAME, for: UIControlState.normal) labelbutton.sizeToFit() if(user["profile_photo_url"] != nil) { print(" ENCONTRO PROFILE PHOTO URL NOT NIL Y ES \(user["profile_photo_url"])") let photoURL = user["profile_photo_url"] as! String let a = LoginService.sharedInstance a.downloadImage(url: photoURL, complete: { (complete) in if (complete) { button.setImage(LoginService.sharedInstance.profile_photo! , for: UIControlState.normal) button.layer.cornerRadius = 0.5 * button.bounds.size.width // button.imageView!.contentMode = .scaleAspectFit // button.imageView!.frame = CGRect(x: 0, y: 0, width: 40, height: 40) //button.imageView!.contentMode = .scaleAspectFit //button.imageView!.clipsToBounds = true //button.imageView!.layer.cornerRadius = 60 button.clipsToBounds = true self.NavigationItem.rightBarButtonItems = [buttomItem,labelItem] } }) } else { self.NavigationItem.rightBarButtonItem = labelItem } print(" EL FRAME DEL BUTTON ES \(button.frame)") } else { labelbutton.setTitle("Login", for: UIControlState.normal) labelbutton.sizeToFit() self.NavigationItem.rightBarButtonItem = labelItem }
-
Vlad Khambir about 7 yearsDid you use stack view in the navigation bar?
-
lorenzo gonzalez about 7 years@V.Khambir Nop... :/
-
Edu almost 7 yearsis this bug report anywhere?
-
onmyway133 over 6 yearsiOS 11 uses AutoLayout to layout navigation items. In case you need to shift the
UIButton
insideUIBarButtonItem
, usebutton.imageEdgeInsets = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: -20)
-
-
stonedauwg almost 7 yearsThis worked for me as well, but can anyone explain why this is necessary for iOS 11 when it never was before?
-
mangerlahn almost 7 yearsUINavigationBar does now layout its subviews using Auto Layout
-
xaphod almost 7 yearsDon't make the same mistake I did: I turned off
translatesAutoresizingMaskIntoConstraints
and then later found out that totally broke iOS 9 (but looked fine on iOS 10 and 11) -
Karoly Nyisztor almost 7 yearsCool. Actually, I needed the Objective-C version, too. Btw, Xcode 9 keeps randomly resizing the navbar items in the storyboard. I have to double-check each time before pushing my changes. Hope this gets eventually fixed soon.
-
david over 6 years@V.Khambir now i am getting this issue. But with this same solution with xcode 9, and if i run in ios 1 device its fine..But if i run in ios 10 version device..my bar button images r not at all showing. How can i fix for all version for this . I checked in device of both ios 11, ios 10. Only showing good in ios 1 version. in ios 10, image not at all showing
-
Vlad Khambir over 6 years@spikesa, it should work on the both iOS versions, probably you have set incorrect constraints.
-
Ryan Brodie over 6 years
Value of type 'UIBarButtonItem' has no member 'widthAnchor'
in Xcode 9 inside anif #available(iOS 11.0, *)
conditional? -
Ryan Brodie over 6 years@V.Khambir Value of type 'UIBarButtonItem' has no member 'widthAnchor' in Xcode 9 inside an if #available(iOS 11.0, *) conditional?
-
jped over 6 years@V.Khambir this doesn't seem to work on anything below iOS 11. How do you fix it for iOS 9 & 10?
-
swalkner over 6 years@jped did you find a solution for this? It doesn't work for me as well on iOS 10 with Xcode 9
-
swalkner over 6 years@jped Update: I now see that the botton is there but in the very top of my app; the toolbar is on the bottom, so there's something messed up with the y-coordinate...
-
swalkner over 6 years@jped Update2: in iOS 10 I have to set the centerYAnchor to the one of the toolbar to make it work, in iOS 11 it crashes with that - weird.
-
Paulo Sigales over 6 yearsBecause navigationbar in ios10 is autoresizing and ios11 is autolayout, you need handle with if #available(iOS 11, *){ }
-
Samarth Kejriwal over 6 years@V.Khambir I have used the following code to set the navigation bar left and right bar button item, ` navigationItem.rightBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: self, action: #selector(submit)) navigationItem.rightBarButtonItem?.image = UIImage(named : "tick") navigationItem.leftBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: self, action: #selector(dismissview)) navigationItem.leftBarButtonItem?.image = UIImage(named : "cancel")` . How to make the above changes on this code
-
GONeale over 6 yearsGreat. Gotta love these breaking changes. Has Apple documented a list of these types of changes on a page or release notes somewhere?
-
Sentry.co over 6 yearsThis works, however the button stops working when you add it in a view. Any tips?
-
iPatel over 6 years@GitSync Check your view's height it will be 0 change it to 44 or whatever you want and make clipToBound = true and then set button.
-
Sentry.co over 6 yearsWow. works! Pro tip: use .pdf assets instead of .png
-
Shobhakar Tiwari over 6 yearsI was going the through the new changes and i found this question , but this answer i guess developer should use
-
Brittany over 6 yearsGreat, simple answer. Thank you. Nothing else was working and it was driving me crazy.
-
Clifton Labrum over 6 yearsThanks for the iOS 10 tip! I had the iOS 11 fix working but couldn't figure it out for iOS 10.
-
igrek over 6 yearsis the container view necessary? Can't i just use UIButton directly?
-
Alessandro Ornano over 6 yearsGreat idea! Applied this one the
UIButton
works very well. -
javal88 over 6 years@lorenzo-gonzalez How did you make it round? I'm stuck on this.
-
lorenzo gonzalez over 6 years@AlessandroLucarini the make it round part is easy : button.layer.cornerRadius = 0.5 * button.bounds.size.width , button.clipsToBounds = true , of course must have height and width contraints in a 1:1 ratio .. 32x32, 50x50..etc.. .. let me know how it goes!
-
javal88 over 6 yearsYes i didn't understood that i'd to add the constraint lines instead of replacing the frame section. Thanks for the advice.
-
lorenzo gonzalez over 6 years@Alessandro Lucarini did you get it working ? Send me your code to [email protected] , i can take a look...
-
Marosdee Uma about 6 yearsyou are my hero, because i need to refactor old project with objective-c.