I'm using a segmented control as sub tabs for a tab bar controller. I have a button on the main tab that's supposed to transition to the second tab (the one with the sub tabs) and programmatically switch the UISegmentedControl to the first tab (0 index).
Of course, tapping on the segmented control works fine. But, when I try to change the tab programmatically using selectedSegmentIndex
, the tab that get's deselected does not update it's font color, which makes the label seem to disappear.
Every post I've read about how to change tabs programmatically indicates that I'm doing it the right way. Can anyone tell me what I'm doing wrong? Thank you for your help!
Here is the code:
class AdvertisingViewController: BaseViewController, TabbedController, ClientSelectorController {
var clientSelectorView: ClientSelector?
var tabControl: UISegmentedControl!
var tabView: UIView!
var nextTabIndex: Int? = nil
var activeTab: AdvertisingTabContent? = nil
var tabs: [AdvertisingTabContent]!
let margin: CGFloat = 20
override func viewDidLoad() {
super.viewDidLoad()
// Initialize the tab view.
tabView = UIView()
view.addSubview(tabView!)
// Initialize the tab controls.
tabControl = UISegmentedControl()
tabControl.insertSegment(withTitle: "Calendar", at: 0, animated: false)
tabControl.insertSegment(withTitle: "TV", at: 1, animated: false)
tabControl.insertSegment(withTitle: "Radio", at: 2, animated: false)
tabControl.insertSegment(withTitle: "Search", at: 3, animated: false)
tabControl.insertSegment(withTitle: "Display", at: 4, animated: false)
tabControl.selectedSegmentIndex = 0
tabControl.addTarget(self, action: #selector(selectedTab(sender:)), for: .valueChanged)
view.addSubview(tabControl!)
// Tab control styles.
let font = UIFont.systemFont(ofSize: 12)
tabControl.setTitleTextAttributes([
NSAttributedStringKey.font: font,
NSAttributedStringKey.foregroundColor: Color.lightGrey
], for: .normal)
tabControl.removeBorders()
// Intialize the tabs.
nextTabIndex = nil
tabs = [
CampaignsTab(view: tabView),
TVTab(view: tabView),
RadioTab(view: tabView),
PaidSearchTab(view: tabView),
DisplayTab(view: tabView),
]
// Bind clientSelector button to clientSelectButtonPressed method.
initializeClientSelector()
// Set the background color.
tabView.backgroundColor = Color.backgroundColor
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Update client selector title.
layoutClientSelector()
// Update tab view & segmented control
let controlHeight: CGFloat = 35
tabControl.frame = CGRect(x: margin, y: clientSelectorView!.frame.height, width: view.frame.width - (margin * 2), height: controlHeight)
// Update the tab view.
tabView.frame = CGRect(x: 0, y: clientSelectorView!.frame.height + controlHeight + margin, width: view.frame.width, height: view.frame.height - clientSelectorView!.frame.height - controlHeight - margin)
// Build tab.
buildTab()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// Update the tabControl.
if let next = nextTabIndex {
if next != tabControl.selectedSegmentIndex {
tabControl.selectedSegmentIndex = next
}
nextTabIndex = nil
}
}
func clientSelectorClicked(selectorModal: UIViewController) {
present(selectorModal, animated: true, completion: nil)
}
// MARK: - Tabs Control
/**
The user selected a different tab.
*/
@objc func selectedTab(sender: UIButton) {
buildTab()
}
/**
A tab was selected from another part of the app.
(This is called before viewWillAppear from another tab)
*/
func switchToTab(atIndex index: Int) {
nextTabIndex = index
}
func buildTab() {
// Clean up the old tab.
activeTab?.cleanUp()
activeTab = nil
// Check next index.
var index = tabControl.selectedSegmentIndex
if let next = nextTabIndex {
index = next
}
// Add/Build the new tab.
if index >= 0 && tabs.count > index {
activeTab = tabs[index]
activeTab?.buildViews()
}
}
}
Update:
Spent a couple more hours looking for a solution this morning. I also tried hacking it by finding the label in the subviews of the segmented control, and manually changing the font color. I could change the text of the label, but not the font color. Something is overriding it.
Is there some other way to programmatically change the selected index? Do I need to submit a ticket to apple? Is nobody else having this problem? Thanks in advance for any help you can provide.
After much struggling, I finally found an answer. I'm removing the borders using the method from the following post:
Swift: How to remove border from segmented control
extension UISegmentedControl {
func applyAppStyles() {
setBackgroundImage(imageWithColor(color: Color.contentBackgroundColor), for: .normal, barMetrics: .default)
setBackgroundImage(imageWithColor(color: Color.orange), for: .selected, barMetrics: .default)
setDividerImage(imageWithColor(color: UIColor.clear), forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default)
}
// create a 1x1 image with this color
private func imageWithColor(color: UIColor) -> UIImage {
let rect = CGRect(x: 0.0, y: 0.0, width: 1.0, height: 1.0)
UIGraphicsBeginImageContext(rect.size)
let context = UIGraphicsGetCurrentContext()
context!.setFillColor(color.cgColor);
context!.fill(rect);
let image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image!
}
}
My first call to setBackgroundImage
is causing the issue; I'm not sure why. But the following code fixes it:
tabControl.setTitleTextAttributes([
NSAttributedStringKey.foregroundColor: Color.darkGreyBlue
], for: .selected)