8

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?

socratesss
  • 81
  • 1
  • 3

5 Answers5

4

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)
Kqtr
  • 5,824
  • 3
  • 25
  • 32
Uday Naidu
  • 532
  • 1
  • 6
  • 16
  • 1
    Apparently [there’s a bug in iOS 11](https://openradar.appspot.com/34276488). This works on iOS 10 for me, but not on iOS 11. – plindberg Feb 01 '18 at 13:18
0

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!

cnotethegr8
  • 7,342
  • 8
  • 68
  • 104
  • @AlexandruMotoc when I created this answer the solution worked. Had you mentioned it doesn't work anymore I would have investigated the problem and updated the answer. The reason for your downvote is wrong and unproductive. I advise you to read the voting rules for your own benefit of getting the most out of this site. – cnotethegr8 Jul 12 '19 at 04:28
  • You can edit the answer with something that works so I can remove the downvote :) Further, I still think it's a bad solution to observe private keypaths like "view.badge.label.font", the reason being obvious :) – Alexandru Motoc Jul 15 '19 at 08:16
  • When the solutions are bad or worse, I think it's obvious which to choose. – cnotethegr8 Jul 15 '19 at 08:37
0

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)
      }
    }
  }

}
SSS04
  • 11
  • 1
0

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)
Husam
  • 8,149
  • 3
  • 38
  • 45
-3

Swift 3

UITabBarItem.appearance().setTitleTextAttributes([NSFontAttributeName: UIFont.systemFont(ofSize: 10)], for: .normal)
UITabBarItem.appearance().setTitleTextAttributes([NSFontAttributeName: UIFont.systemFont(ofSize: 10)], for: .selected)
Bogdan Ustyak
  • 5,639
  • 2
  • 21
  • 16