Home > Net >  How to fix the size of UIBarButtonItem when its font weight changes
How to fix the size of UIBarButtonItem when its font weight changes

Time:09-26

Below is a short piece of demo code distilled from my project. It consists of a UINavigationBar, UINavigationItem, and several UIBarButtonItems. Tapping on a barButtonItem highlights it and dims the others. In doing so, it is understandable that the font size changes, but I want the size of the barButtonItems themselves to be fixed. That way, when I tap randomly on the barButtonItems, they don't appear to jiggle as their title text shrinks and expands. How do I make the barButtonItems resist resizing as their title text changes?

import UIKit

class ViewController: UIViewController {
    
    var barButtonItems: [UIBarButtonItem]!

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .darkGray
        
        let navBar: UINavigationBar = UINavigationBar(frame: CGRect(x: 0, y: 100, width: view.frame.width, height: 40))
        navBar.barTintColor = #colorLiteral(red: 0.1019607857, green: 0.2784313858, blue: 0.400000006, alpha: 1)
        view.addSubview(navBar)
        
        let navItem = UINavigationItem()
        let appleBarBtnItem  = UIBarButtonItem(title: "Apple", style: .plain, target: self, action: #selector(barItemTapped))
        let bananaBarBtnItem = UIBarButtonItem(title: "Banana", style: .plain, target: self, action: #selector(barItemTapped))
        let kiwiBarBtnItem = UIBarButtonItem(title: "Kiwi", style: .plain, target: self, action: #selector(barItemTapped))
        let pearBarBtnItem = UIBarButtonItem(title: "Pear", style: .plain, target: self, action: #selector(barItemTapped))
        let orangeBarBtnItem = UIBarButtonItem(title: "Orange", style: .plain, target: self, action: #selector(barItemTapped))
        barButtonItems = [appleBarBtnItem, bananaBarBtnItem, kiwiBarBtnItem, pearBarBtnItem, orangeBarBtnItem]

        navItem.leftBarButtonItems = barButtonItems
        navBar.setItems([navItem], animated: false)
        
        setCurrentBarItem(appleBarBtnItem)
    }
    
    func setCurrentBarItem(_ barBtnItem: UIBarButtonItem) {
        for btn in barButtonItems {
            highlight(btn, turnedOn: (btn == barBtnItem) )
        }
    }
    
    func highlight(_ button: UIBarButtonItem, turnedOn: Bool) {
        button.tintColor = #colorLiteral(red: 0.7230747342, green: 0.9554787278, blue: 0.9893732667, alpha: 1)
        let weight: UIFont.Weight = turnedOn ? .bold : .thin
        let attributes: [NSAttributedString.Key : Any] = [ .font: UIFont.systemFont(ofSize: 20, weight: weight)]
        button.setTitleTextAttributes(attributes, for: .normal)
    }
    
    @objc func barItemTapped(_ sender: UIBarButtonItem) {
        setCurrentBarItem(sender)
    }
}

barButtonItems change size as their titles change size

CodePudding user response:

One reason they are jiggling is that you are setting setTitleTextAttributes only for .normal state. Add it for .selected as well so it jiggle less however it won't fully fix your issue. Sth like this

button.setTitleTextAttributes(attributes, for: .selected)

I would suggest to try to add some margin to the ui text holder element of the UIBarButtonItems. May fix it!

CodePudding user response:

Looks like I have to give up on having a .bold font weight for the selected barButtonItem and a .thin font weight when it's not, because the change in font weight expands or shrinks the width of the barButtonItem causing the juxtaposing barButtonItems to shift and jiggle around when I tap on them. I finally decided on only changing the colors of the barButtonItems and providing a simple animation:

    func highlight(_ button: UIBarButtonItem, turnedOn: Bool) {
        let tintColor = turnedOn ? 
            #colorLiteral(red: 0.7230747342, green: 0.9554787278, blue: 0.9893732667, alpha: 1) 
            : 
            #colorLiteral(red: 0.1901655495, green: 0.5488880277, blue: 0.7976593971, alpha: 1)
        
        UIView.animate(withDuration: 0.2, 
                       delay: 0, 
                       options: [.allowUserInteraction, .curveEaseInOut], 
                       animations: { button.tintColor = tintColor }, 
                       completion: nil)
    }

barButtonItem selection visually improved

  • Related