I'm trying to set the font weight of a selected tab bar item to bold font. It seems as it has no effect. Any idea what is wrong. forState: .Normal
works as expected, forState: .Selected
has no effect.
let tabBarItem0 = tabBar.items![0] as! UITabBarItem
var selectedImage0 : UIImage = UIImage(named:"ic_tabbar_item_one")!.imageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal)
var fontLight:UIFont = UIFont(name: "HelveticaNeue-UltraLight", size: 12)!
var fontBold:UIFont = UIFont(name: "HelveticaNeue-Bold", size: 12)!
tabBarItem0.image = unselectedImage0
tabBarItem0.selectedImage = selectedImage0
tabBarItem0.title = "Overview"
tabBarItem0.setTitleTextAttributes(
[
NSForegroundColorAttributeName: UIColor.whiteColor(),
NSFontAttributeName: fontLight
], forState: .Normal)
tabBarItem0.setTitleTextAttributes(
[
NSForegroundColorAttributeName: UIColor.whiteColor(),
NSFontAttributeName: fontBold
], forState: UIControlState.Selected)
In Storyboard, give a unique Tag to each UITabBarItem you have: For every tab -> Select it and go to it's "Attributes Inspector" -> Give each one a unique number in the "Tag" field but you should not use zero (I used 1 through 4).
This sets us up for later, to identify which tab is pressed.
Create a new subclass of UITabBarController and then assign it: FILE -> New File -> iOS Cocoa Touch -> create a Subclass of UITabBarController. Assign the new .swift file to your UITabBarController under "Identity Inspector."
We will need custom logic in our UITabBarController.
Create a new subclass of UITabBarItem, assign the same file to all of your UITabBarItems: FILE -> New File -> iOS Cocoa Touch -> create a Subclass of UITabBarItem and assign the same one to all of your tabs.
We will need a shared custom logic in our tab bar items.
Add this code to your UITabBarItem subclass, it sets up the initial state (primary tab bold, the rest unselected) and will allow for programmatic tab changes as well:
class MyUITabBarItemSubclass: UITabBarItem {
//choose initial state fonts and weights here
let normalTitleFont = UIFont.systemFont(ofSize: 12, weight: UIFontWeightRegular)
let selectedTitleFont = UIFont.systemFont(ofSize: 12, weight: UIFontWeightBold)
//choose initial state colors here
let normalTitleColor = UIColor.gray
let selectedTitleColor = UIColor.black
//assigns the proper initial state logic when each tab instantiates
override func awakeFromNib() {
super.awakeFromNib()
//this tag # should be your primary tab's Tag*
if self.tag == 1 {
self.setTitleTextAttributes([NSFontAttributeName: selectedTitleFont, NSForegroundColorAttributeName: selectedTitleColor], for: UIControlState.normal)
} else {
self.setTitleTextAttributes([NSFontAttributeName: normalTitleFont, NSForegroundColorAttributeName: normalTitleColor], for: UIControlState.normal)
}
}
}
Here we set up the initial state so that the tabs are set correctly when the app opens up, we'll take care of the physical tab presses in the next subclass.
Add this code to your UITabBarController subclass, it's the logic for assigning the correct states as you press on the tabs.
class MyUITabBarControllerSubclass: UITabBarController {
//choose normal and selected fonts here
let normalTitleFont = UIFont.systemFont(ofSize: 12, weight: UIFontWeightRegular)
let selectedTitleFont = UIFont.systemFont(ofSize: 12, weight: UIFontWeightBold)
//choose normal and selected colors here
let normalTitleColor = UIColor.gray
let selectedTitleColor = UIColor.black
//the following is a delegate method from the UITabBar protocol that's available
//to UITabBarController automatically. It sends us information every
//time a tab is pressed. Since we Tagged our tabs earlier, we'll know which one was pressed,
//and pass that identifier into a function to set our button states for us
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
setButtonStates(itemTag: item.tag)
}
//the function takes the tabBar.tag as an Int
func setButtonStates (itemTag: Int) {
//making an array of all the tabs
let tabs = self.tabBar.items
//looping through and setting the states
var x = 0
while x < (tabs?.count)! {
if tabs?[x].tag == itemTag {
tabs?[x].setTitleTextAttributes([NSFontAttributeName: selectedTitleFont, NSForegroundColorAttributeName: selectedTitleColor], for: UIControlState.normal)
} else {
tabs?[x].setTitleTextAttributes([NSFontAttributeName: normalTitleFont, NSForegroundColorAttributeName: normalTitleColor], for: UIControlState.normal)
}
x += 1
}
}
}
It looks like this was such a pain because for some reason the tabs do not recognize state changes into ".Selected". We had to do everything by working with .Normal states only - basically detecting the state changes ourselves.
Hope this helped!
I've faced the same issue when tried to change font of selected item. Looks like titleTextAttributes' font parameter is only useful when setting them to normal state. That's why I implemented UITabBarControllerDelegate
where I update attributes for currently selected item. You should call updateSelection()
method after UITabBarController
s loadView()
too. Or you can call updateSelection()
method in overridden selectedItem
setter.
extension TabBarController: UITabBarControllerDelegate {
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
updateSelection()
}
func updateSelection() {
let normalFont = Fonts.Lato.light.withSize(10)
let selectedFont = Fonts.Lato.bold.withSize(10)
viewControllers?.forEach {
let selected = $0 == self.selectedViewController
$0.tabBarItem.setTitleTextAttributes([.font: selected ? selectedFont : normalFont], for: .normal)
}
}
}
When I try to change font of selected tab by using UITabBarItem but it doesn't work. Adoption of delegate is suggested to get informed when tab changes. I just put pieces together.
private class MyTabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
delegate = self
}
override func setViewControllers(_ viewControllers: [UIViewController]?, animated: Bool) {
super.setViewControllers(viewControllers, animated: animated)
updateTabBarAppearance()
}
}
extension MyTabBarController: UITabBarControllerDelegate {
public func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
updateTabBarAppearance()
}
func updateTabBarAppearance() {
self.tabBar.tintColor = .red
let unselectedLabelFont = UIFont.systemFont(ofSize: 18, weight: .regular)
let selectedLabelFont = UIFont.systemFont(ofSize: 20, weight: .semibold)
let labelColor = UIColor.init(red: 38/255.0, green: 38/255.0, blue: 38/255.0, alpha: 1.0)
let selectedIconColor = UIColor.init(red: 8/255.0, green: 8/255.0, blue: 8/255.0, alpha: 1.0)
viewControllers?.forEach {
let isSelected = $0 == self.selectedViewController
let selectedFont = isSelected ? selectedLabelFont : unselectedLabelFont
$0.tabBarItem.setTitleTextAttributes([.font: selectedFont, .foregroundColor: labelColor], for: .normal)
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With