When setting UIBarButtonItem in previous versions of iOS I’ve been able to reliably control the size of buttons by using a UIButton initialized with a frame. In iOS 11 this has changed as UINavigationItem now [finally] uses AutoLayout.

The easy solve for this, using SnapKit looks like:

let button = UIButton()
button.setImage(UIImage(named: "btn-img"), for: .normal)
button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
let barItem = UIBarButtonItem(customView: button)

barItem.customView?.snp.makeConstraints({ (make) in
  make.width.equalTo(22)
  make.height.equalTo(22)
})

And if you’re using vanilla AutoLayout:

let button = UIButton()
button.setImage(UIImage(named: "btn-img"), for: .normal)
button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
let barItem = UIBarButtonItem(customView: button)

let width = barItem.customView?.widthAnchor.constraint(equalToConstant: 22)
width.isActive = true
let height = barItem.customView?.heightAnchor.constraint(equalToConstant: 22)
height.isActive = true

Extra bonus: you can also safely connect your bar buttons to custom navigation item titleView’s to avoid buttons overlaying your title content. This is a great improvement to have in iOS 11 and should obviate the need for the UINavigationBar hacking of yore.