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)
FOUND THE SOLUTION (Swift 3, XCode 8.1)
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.
You can programmatically change the tabs and still detect state changes by... I'll update this later if anyone has an interest, just ask.
Hope this helped!
UITabBarItem.appearance().setTitleTextAttributes(
[NSFontAttributeName: UIFont(name:"your_font_name", size:11)!,
NSForegroundColorAttributeName: UIColor(rgb: 0x929292)],
forState: .Normal)
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 UITabBarControllers 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)
}
}
}
Build Settings\Swift Language Version: 4.1
General\Deployment Target: 10.3
import UIKit
class FirstViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let attrsNormal = [NSAttributedStringKey.foregroundColor : UIColor.black,
NSAttributedStringKey.font : UIFont(name: "Arial", size: 14)!]
UITabBarItem.appearance().setTitleTextAttributes(attrsNormal,
for: UIControlState.normal)
let attrsSelected = [NSAttributedStringKey.foregroundColor : UIColor.red,
NSAttributedStringKey.font : UIFont(name: "Arial", size: 14)!]
UITabBarItem.appearance().setTitleTextAttributes(attrsSelected,
for: UIControlState.selected)
}
...
}
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)
}
}
}
To set the TitleTextAttribute, you should use the appearance proxy like: [UIBarItem appearance]
The problem is that the state of tabBarItem0 is not changed to Selected. Because this is UITabBarItem which represents a single element of a UITabBar. So, you can not directly change the status using UITabBarItem API. You have to change it state by assigning selectedItem.
This information is gained from documentation and I suggest all programmers to have skills like this. Hopefully, this will help.
Related
I have a custom UINavigationController like so:
class CustomNavigationController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
delegate = self
setupDefaultAppearance()
}
private func setupDefaultAppearance() {
UINavigationBar.appearance().tintColor = R.color.textBlack()
let titleAttributes: [NSAttributedString.Key: Any] = [ .font: R.font.interMedium(size: 18)! ]
UINavigationBar.appearance().titleTextAttributes = titleAttributes
// Hide the title in bar button items
let backButtonAttributes: [NSAttributedString.Key: Any] = [ .font: UIFont(name: "Helvetica-Bold", size: 0.1)!,
.foregroundColor: UIColor.clear]
UIBarButtonItem.appearance().setTitleTextAttributes(backButtonAttributes, for: .normal)
UIBarButtonItem.appearance().setTitleTextAttributes(backButtonAttributes, for: .highlighted)
}
}
However, the code to hide the title in bar button items screwed IQKeyboardManager. The Done button (or any button on the toolbar) in the keyboard or any picker view is gone now because of this. So, I believe I should not use the UIBarButtonItem.appearance() static func. How do I remove the title of the Navigation Controller's back button without making the bug in the keyboard and picker views?
Thanks.
So I've asked the same question to the Apple Developer Forums too. And someone did answered it. Basically, all I need to do is just the appearance is it is contained in the navigation bar like so:
UIBarButtonItem.appearance(whenContainedInInstancesOf: [UINavigationBar.self]).setTitleTextAttributes(backButtonAttributes, for: .normal)
UIBarButtonItem.appearance(whenContainedInInstancesOf: [UINavigationBar.self]).setTitleTextAttributes(backButtonAttributes, for: .highlighted)
I have a view controller where I need to display multiline title on the navigation bar. For this, I have written a protocol like this -
import UIKit
protocol CustomNavigationBar {
func setupNavigationMultilineTitle(titleText: String, prefersLargeTitles: Bool, largeTitleDisplayMode: UINavigationItem.LargeTitleDisplayMode)
}
And then extended it -
extension CustomNavigationBar where Self : UIViewController {
func setupNavigationMultilineTitle(titleText: String, prefersLargeTitles: Bool = true, largeTitleDisplayMode: UINavigationItem.LargeTitleDisplayMode = .automatic ) {
self.navigationController?.navigationBar.prefersLargeTitles = prefersLargeTitles
self.navigationController?.navigationItem.largeTitleDisplayMode = largeTitleDisplayMode
self.navigationController?.navigationBar.largeTitleTextAttributes = [
NSAttributedString.Key.foregroundColor: UIColor.black,
NSAttributedString.Key.font: UIFont.systemFont(ofSize: 18, weight: .semibold)
]
self.title = titleText
if let navBarSubViews = self.navigationController?.navigationBar.subviews {
for navItem in navBarSubViews {
for itemSubView in navItem.subviews {
if let largeLabel = itemSubView as? UILabel {
largeLabel.text = self.title
largeLabel.numberOfLines = 0
largeLabel.lineBreakMode = .byWordWrapping
largeLabel.sizeToFit()
}
}
}
}
}
}
In my view controller, I conform to this protocol and inside viewDidAppear method, I call setupNavigationMultilineTitle method as follows -
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.setupNavigationMultilineTitle(titleText: "This is created for testing This is created for testing This is created for testing This is created for testing This is created for testing")
}
**
This works good on an iPhone running lesser than iOS13.
**
**
However, on an iPhone running greater than iOS 13, it just displays
one line and then truncates.
**
Has there been any changes in the UINavigationBar in iOS13? I researched and found something about background color but nothing related to multi line title using prefersLargeTitles and largeTitleDisplayMode.
Can someone please help me getting this up on iOS13?
Thanks!!
can someone help me out in changing font, size and color in prompt string on my NavigationController?
In the attachment, I want to modify "Consulenze" string.
Thank you everybody
Edit: I already tried the solution found here but no results.
You can try following ways:
1) In viewDidLoad of your ViewController add this lines:
self.navigationController?.navigationBar.tintColor = UIColor.white
let navigationTitleFont = UIFont(name: "Avenir", size: 20)!
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.font: navigationTitleFont]
2) You can create completely custom nav bar, just add UIView to the top your view and add all necessary elements - buttons, labels, etc.
Simply add this code in your ViewController. You can change both the Prompt text and color by using this code -
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
for view in self.navigationController?.navigationBar.subviews ?? [] {
let subviews = view.subviews
if subviews.count > 0, let label = subviews[0] as? UILabel {
label.textColor = UIColor.red
label.font = UIFont.systemFont(ofSize: 30)
}
}
}
}
OUTPUT -
Additional -
I want to change the tintColor of UISegmentedControl selected segment in Swift 3.
I've searched a lot of answers in Objective-c...
This is my code:
class ViewController:UIViewController{
var segment:UISegmentedControl
override func viewDidLoad() {
super.viewDidLoad()
segment.insertSegment(withTitle: "AAA", at: 0, animated: true)
segment.insertSegment(withTitle: "BBB", at: 1, animated: true)
segment.insertSegment(withTitle: "CCC", at: 2, animated: true)
segment.addTarget(self, action: #selector(changeValue), for: .valueChanged)
segment.selectedSegmentIndex = 0
view.addSubview(segment)
}
func changeValue(sender:AnyObject) {
//I don't know how to do that change color when segment selected
//
}
}
Thanks!
Use the code below for above ios 13,
if #available(iOS 13.0, *) {
segment.selectedSegmentTintColor = .red
} else {
segment.tintColor = .red
}
To programmatically change tint color of segment,
segment.tintColor = UIColor.yellow
if you want to set the color of the title for example, you can do it like this:
let titleTextAttributes = [NSForegroundColorAttributeName: Color.blue]
segmentedControl.setTitleTextAttributes(titleTextAttributes, forState: .Selected)
In Main.storyboard, select segmentControl and change the property "Tint" as shown in below screenshot:
If you create the segmentedControl programmatically, then use this:
segment.tintColor = UIColor.red
A new property was added in iOS 13: selectedSegementTintColor. The old tintColor property no longer works in iOS 13.
You can find a more complete writeup of the changes here iOS 13 UISegmentedControl: 3 important changes
Add the following code to your changeValue function:
func changeValue(sender: UISegmentedControl){
for i in 0..<sender.subviews.count {
if sender.subviews[i].isSelected() {
var tintcolor = UIColor.red // choose the color you want here
sender.subviews[i].tintColor = tintcolor
}
else {
sender.subviews[i].tintColor = nil
}
}
}
This is a swift version of the accepted answer from this question: UISegmentedControl selected segment color
in my table view controller it works fine and I can configure the view like so:
func configureView() {
self.tableView.backgroundView = UIImageView(image: UIImage(named: "background.jpg"))
//set custom height for tableview row
tableView.rowHeight = 64
//change the font and size of nav bar text
if let navBarFont = UIFont(name: "HelveticaNeue-Thin", size: 20.0) {
let navBarAttributesDictionary: [String: AnyObject]? = [NSForegroundColorAttributeName: UIColor.blackColor(), NSFontAttributeName: navBarFont]
navigationController?.navigationBar.titleTextAttributes = navBarAttributesDictionary
}
}
When I am trying to configure the view in another view controller (with the same navigation controller) it doesn't work and won't change the background or nav bar font, i use this configureview:
func configureView() {
self.view.backgroundColor = UIColor(patternImage: UIImage(named: "background.jpg")!)
//change the font and size of nav bar text
if let navBarFont = UIFont(name: "HelveticaNeue-Thin", size: 20.0) {
print("fired")
let navBarAttributesDictionary: [String: AnyObject]? = [NSForegroundColorAttributeName: UIColor.blackColor(), NSFontAttributeName: navBarFont]
UINavigationBar.appearance().tintColor = UIColor.redColor()
navigationController?.navigationBar.titleTextAttributes = navBarAttributesDictionary
}
}
Does anyone have any suggestions on how to debug this or what could be going on? My first view controller is a table view, second a normal view. Thanks
Edit: my segue is of type Show, and my prepare for segue is as follows:
if segue.identifier == "showAlertInfoSegue" {
if let viewController = segue.destinationViewController as? AlertViewController {
viewController.tableAlert = nil
//if the sender is the selected table view row - load in the data from the data struct
if sender?.tag != 1 {
viewController.tableAlert = alertDetail
}
viewController.onDataAvailable = {[weak self]
(data) in
if let weakSelf = self {
weakSelf.doSomethingWithData(data)
}
}
viewController.hidesBottomBarWhenPushed = true
}
}
I also see a peculiar grey shadow appearing on the top nav bar when transitioning, then it dissapears