socratesss
socratesss

Reputation: 81

Swift - How to change UITabBarItem badge font?

I have a UITabBar. I set a value for tab bar items:

tabBarItem3?.badgeValue = String(self.numberOfProducts)

Now I want to change its font to a specific font. Then I used this code :

tabBarItem3?.setBadgeTextAttributes([NSFontAttributeName: UIFont(name: "IRANSans", size: 14)], for: .normal)

It doesn't work. What should I do?

Upvotes: 8

Views: 5422

Answers (5)

Husam
Husam

Reputation: 8568

For iOS15+

let tabBarAppearance: UITabBarAppearance = UITabBarAppearance()
tabBarAppearance.configureWithOpaqueBackground()

tabBarAppearance.stackedLayoutAppearance.normal.badgeTextAttributes = [
    .font: UIFont.systemFont(ofSize: 11)
]

// also can change title:
// tabBarAppearance.stackedLayoutAppearance.normal.titleTextAttributes = [...]
// tabBarAppearance.stackedLayoutAppearance.selected.titleTextAttributes = [...]

UITabBar.appearance().standardAppearance = tabBarAppearance
UITabBar.appearance().scrollEdgeAppearance = tabBarAppearance

For iOS14 and below

UITabBarItem.appearance().setBadgeTextAttributes([
            .font: UIFont.systemFont(ofSize: 11)
        ], for: .normal)

Upvotes: 0

Uday Naidu
Uday Naidu

Reputation: 532

Swift 3

UITabBarItem.appearance().setBadgeTextAttributes([.font: UIFont.systemFont(ofSize: 30, weight: .medium)], for: .normal)
UITabBarItem.appearance().setBadgeTextAttributes([.font: UIFont.systemFont(ofSize: 30, weight: .medium)], for: .selected)

Upvotes: 4

SSS04
SSS04

Reputation: 11

Try this two functions from UITabBarController extension:

var tabBarController : UITabBarController

bottomBar = UITabBarController()

... 
... 
... 

 // Change badge font size
bottomBar.setBadgeFontSize(fontSize: 10.0)


 // Change badge font
bottomBar.setBadgeFont(font: UIFont.boldSystemFont(ofSize: 12.0)) 

Swift 4

extension UITabBarController {

  /**

   Change the badge font size of an UITabBarController item.

   - Parameter fontSize: new font size
   - Parameter subviews: nil or optional when called from UITabBarController object.

   Example of usage (programmatically):

   ```
   let bottomBar = UITabBarController()
   ...
   ...
   ...
   bottomBar.setBadgeFontSize(fontSize: 10.0)
   ```
   */
  func setBadgeFontSize(fontSize: CGFloat, subviews: [UIView]? = nil) {

    let arraySubviews = (subviews == nil) ? self.view.subviews : subviews!

    for subview in arraySubviews {
      let describingType = String(describing: type(of: subview))
      if describingType == "_UIBadgeView" {
        for badgeSubviews in subview.subviews {
          let badgeSubviewType = String(describing: type(of: badgeSubviews))
          if badgeSubviewType == "UILabel" {
            let badgeLabel = badgeSubviews as! UILabel
            badgeLabel.fontSize = fontSize
            break
          }
        }
      } else {
        setBadgeFontSize(fontSize: fontSize, subviews: subview.subviews)
      }
    }

  }

  /**

   Change the badge font size of an UITabBarController item.

   - Parameter font: new font
   - Parameter subviews: nil or optional when called from UITabBarController object.

   Example of usage (programmatically):

   ```
   let bottomBar = UITabBarController()
   ...
   ...
   ...
   bottomBar.setBadgeFont(font: UIFont.boldSystemFont(ofSize: 12.0))
   ```
   */
  func setBadgeFont(font: UIFont, subviews: [UIView]? = nil) {

    let arraySubviews = (subviews == nil) ? self.view.subviews : subviews!

    for subview in arraySubviews {
      let describingType = String(describing: type(of: subview))
      if describingType == "_UIBadgeView" {
        for badgeSubviews in subview.subviews {
          let badgeSubviewType = String(describing: type(of: badgeSubviews))
          if badgeSubviewType == "UILabel" {
            let badgeLabel = badgeSubviews as! UILabel
            badgeLabel.font = font
            break
          }
        }
      } else {
        setBadgeFont(font: font, subviews: subview.subviews)
      }
    }
  }

}

Upvotes: 0

cnotethegr8
cnotethegr8

Reputation: 7510

UIKit updates the badge font sometime after the view's layoutSubviews or viewWillAppear. Fully overriding this will need a bit of code. You want to start by observing the badge's font change.

tabBarItem.addObserver(self, forKeyPath: "view.badge.label.font", options: .new, context: nil)

Now once the observe method is called it's safe to set the badge font. There's one catch however. UIKit wont apply the same change twice. To get around this issue first set the badge attributes to nil and then reapply your font.

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if keyPath == "view.badge.label.font" {
        let badgeAttributes = [NSFontAttributeName: UIFont(name: "IRANSans", size: 14)]
        tabBarItem?.setBadgeTextAttributes(nil, for: .normal)
        tabBarItem?.setBadgeTextAttributes(badgeAttributes, for: .normal)

    } else {
        super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
    }
}

Just incase of future iOS updates, you might want to wrap the addObserver in a try-catch. Also don't forget to remove the observer when your done!

Upvotes: 0

Bogdan Ustyak
Bogdan Ustyak

Reputation: 5837

Swift 3

UITabBarItem.appearance().setTitleTextAttributes([NSFontAttributeName: UIFont.systemFont(ofSize: 10)], for: .normal)
UITabBarItem.appearance().setTitleTextAttributes([NSFontAttributeName: UIFont.systemFont(ofSize: 10)], for: .selected)

Upvotes: -3

Related Questions