I have a firstViewController which has a UISegmentedControl and SegmentedControl has two tabs button. its all working fine but when i go to next SecondViewController. On SecondViewController there is a link for webView when i push to that webView & then back to SecondViewController and then back to firstViewController by tapping back button. The SegmentedControl leave its position & it moves below the NavigationController
firstViewController Code is :
override func viewDidLoad() {
super.viewDidLoad()
setupMenuBar()
setupViewControllerUI()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
setupNavigationBarUI()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewDidAppear(animated)
// to avoid getting a black navigationBar while transition
navigationController?.navigationBar.barTintColor = UIColor.white
self.navigationController?.navigationBar.setBackgroundImage(UIColor.white.convertImage(), for: UIBarMetrics.default)
navigationController!.navigationBar.titleTextAttributes = [ NSFontAttributeName: UIFont.appThemeRegularFontWithSize(20.0), NSForegroundColorAttributeName: UIColor.lightGray]
}
// MARK: - UIViewController Helper Method
func setupViewControllerUI() {
if isFirstVC {
AppUtility.switchToViewController(viewController: firstViewController!, in: self)
segmentedControl.selectedSegmentIndex = 0
} else {
LoadingViewController.sharedLoader.showLoading(self.navigationController!)
AppUtility.switchToViewController(viewController: secondViewController, in: self)
segmentedControl.selectedSegmentIndex = 1
}
}
func setupMenuBar() {
SegmentedControlContainerView.backgroundColor = UIColor.ButtonColorWithAlpha(1.0)
segmentedControl.tintColor = UIColor.white
}
func setupNavigationBarUI() {
navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName : UIColor.white]
navigationController?.navigationBar.barTintColor = UIColor.ButtonColorWithAlpha(1.0)
navigationController?.navigationBar.setBackgroundImage(UIColor.ButtonColorWithAlpha(1.0).convertImage(), for: UIBarMetrics.default)
navigationController?.navigationBar.shadowImage = UIColor.white.withAlphaComponent(0.0).convertImage()
navigationController?.view.backgroundColor = UIColor.ButtonColorWithAlpha(1.0)
segmentedControl.setTitle("first", forSegmentAt: 1)
segmentedControl.setTitle("second", forSegmentAt: 0)
self.navigationController?.navigationBar.tintColor = UIColor.white
navigationController?.navigationBar.barStyle = UIBarStyle.default
self.title = "Screen Name"
navigationController?.navigationBar.setNeedsDisplay()
}
Related
im facing the problem of setting the font-color of the title of one ViewController in swift and resetting it when it disappears. Currently I'm able to set the color from black to white with:
override func viewDidLoad() {
let textAttributes = [NSAttributedStringKey.foregroundColor:UIColor.white]
navigationController?.navigationBar.titleTextAttributes = textAttributes
}
override func viewWillDisappear(_ animated: Bool) {
let textAttributes = [NSAttributedStringKey.foregroundColor:UIColor.black]
navigationController?.navigationBar.titleTextAttributes = textAttributes
}
when I try resetting with UIColor.black it doesn't change anything.
when I try to set the whole appearance there is no change at all.
override func viewDidLoad() {
UINavigationBar.appearance().titleTextAttributes = [NSAttributedStringKey.foregroundColor : UIColor.white]
}
override func viewWillDisappear(_ animated: Bool) {
UINavigationBar.appearance().titleTextAttributes = [NSAttributedStringKey.foregroundColor : UIColor.black]
}
How can I still achieve this?
Using Xcode 10.0
Swift 4
Instead of adding the code to viewDidLoad(), add it into viewDidAppear(_:), i.e
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
navigationController?.navigationBar.titleTextAttributes = textAttributes
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.black]
navigationController?.navigationBar.titleTextAttributes = textAttributes
}
Thanks everybody for your help.
I got it working for me with another function:
override func willMove(toParentViewController parent: UIViewController?) {
var textAttributes: [NSAttributedString.Key : Any]?
if parent == nil{ // navigating back
textAttributes = [NSAttributedStringKey.foregroundColor:UIColor.black]
}else{
textAttributes = [NSAttributedStringKey.foregroundColor:UIColor.white]
}
navigationController?.navigationBar.titleTextAttributes = textAttributes
}
This functions is also called when a view is building up.
This solution worked for me and the colors are already set when the view is displayed.
I'm open for pro/cons responds to this.
you can use this function viewWillAppear in your code on any view
func navigationBarProperties(vc:UIViewController, title:String){
vc.navigationController!.navigationBar.isHidden = false
vc.navigationController!.navigationBar.isTranslucent = false
// text color
vc.navigationController!.navigationBar.tintColor = UIColor.white
// bar color
vc.navigationController!.navigationBar.barTintColor = UIColor.black
let isFont = UIFont.init(name: "Helvetica-bold", size: 15)
vc.navigationItem.title = title
vc.navigationController!.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor: #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1) ,NSAttributedStringKey.font: isFont!]
}
override open func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//---nav bar customization----//
navigationBarProperties(vc: self, title: "Home")
}
Subclass UINavigationController and assign it to your navigationController:
class CustomNavigationController : UINavigationController {
let usualTextAttributes: [NSAttributedString.Key: Any] = [.foregroundColor: UIColor.red]
let customTextAttributes: [NSAttributedString.Key: Any] = [.foregroundColor: UIColor.blue]
private func updateTitleColorIfNeeded() {
if topViewController is MyCustomViewController {
navigationBar.titleTextAttributes = customTextAttributes
} else {
navigationBar.titleTextAttributes = usualTextAttributes
}
}
override func popViewController(animated: Bool) -> UIViewController? {
updateTitleColorIfNeeded()
return super.popViewController(animated: animated)
}
override func pushViewController(_ viewController: UIViewController, animated: Bool) {
updateTitleColorIfNeeded()
super.pushViewController(viewController, animated: animated)
}
}
If MyCustomViewController is root of the navigation controller, then set it's initial title color in viewDidLoad:
class MyCustomViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.yellow]
}
}
I have stumbled over sort of glitch. When I load this view first time, everything is okay:
If I go to the next view, my UINavigationBar looks like this:
If I press back now, I cant press the scopeButton which is displayed in the first image.
I know if I remove the UISearchBar(second image), I will be able to press the scopeButtons (first image).
This is my code for first image:
var searchBar = UISearchBar()
override func viewDidLoad() {
secondContainerView.isHidden = true
searchBar.delegate = self
searchBar.placeholder = "Search"
searchBar.scopeButtonTitles = ["0", "1"]
searchBar.tintColor = UIColor.white
searchBar.barTintColor = UIColor(red: 105/255, green: 185/255,
blue: 114/255, alpha: 1.00)
navigationItem.titleView = searchBar
}
This is my code for the second image:
var searchBar = UISearchBar()
override func viewDidLoad() {
searchBar.delegate = self
searchBar.placeholder = "Search"
navigationItem.titleView = searchBar
}
I figured out that if I do this it works:
override func viewWillDisappear(_ animated: Bool) {
searchBar.removeFromSuperview()
}
Sadly this creates another problem, when I do the swipeGesture to go back, and stay on the current view, the UISearchBar is gone.
Edit:
If I tap the back button the scopItems won't respond, but on swipe, it works:
override func viewWillAppear(_ animated: Bool) {
navigationItem.titleView = searchBar
}
override func viewWillDisappear(_ animated: Bool) {
navigationItem.titleView = nil
}
override func viewDidAppear(_ animated: Bool) {
navigationItem.titleView = searchBar
}
hey guys I've used large UINavigationBar in a child ViewController and i want to resize my navBar to default size when popping back to rootViewController smoothly.
vc's gif:https://giphy.com/gifs/1P0HwqlIqqMnzibxbH
EDIT
I don't want to remove largeNavBar from parent vc, i only want to disappear it gradually and with animation like app store:https://giphy.com/gifs/YXsTA6I5r0lGik1gC8
here is the child vc code:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.initUI()
super.enableLargeNavigationTitle(title: (self.favorty?.sellerProduct?.product?.name)!)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
super.removeTitleImage()
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(true)
}
here is the enableLargeNavigationBar function:
func enableLargeNavigationTitle(title: String) {
self.navigationController?.view.backgroundColor = VVUtility.splashBackGroundColor()
self.navigationItem.title = "\(title)".localized()
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor : UIColor.white, NSAttributedStringKey.font : VVUtility.normalFontWithPlusSize(increaseSize: -2.0)]
if #available(iOS 11.0, *) {
self.navigationController?.navigationBar.isTranslucent = false
self.navigationController?.navigationBar.prefersLargeTitles = true
self.navigationController?.navigationBar.backgroundColor = VVUtility.splashBackGroundColor()
self.navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedStringKey.foregroundColor : UIColor.white, NSAttributedStringKey.font : VVUtility.normalFontWithPlusSize(increaseSize: 0.0)]
} else {
// Fallback on earlier versions
}
}
disableLargeNavigation function:
func disableLargeNavigationTitle() {
if #available(iOS 11.0, *) {
self.navigationController?.navigationItem.largeTitleDisplayMode = .never
self.navigationController?.navigationBar.prefersLargeTitles = false
} else {
// Fallback on earlier versions
}
}
here is parent vc code:
override func viewDidLoad() {
super.viewDidLoad()
self.initUI()
self.getData()
super.disableLargeNavigationTitle()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.navigationBar.addSubview(searchBarBoxView)
self.timerDelegate?.startTimer()
self.navigationController?.setNavigationBarHidden(false, animated: true)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.searchBarBoxView.removeFromSuperview()
self.timerDelegate?.stopTimer()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.tabBarController?.delegate = self
super.disableLargeNavigationTitle()
}
This worked for me. Try putting this code in awakeFromNib() for each view controller, with the settings changed as you need.
override func awakeFromNib() {
// Large titles
if #available(iOS 11.0, *) {
navigationController?.navigationBar.prefersLargeTitles = false // This could be true for other view controller
navigationItem.largeTitleDisplayMode = .never // This could be .always for other view controller
navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.black] // Or whatever you want
} else {
// Handle iOS 10 and below (no large titles)
}
}
Alternatively, I think you can do this just in Storyboard, but that didn’t work for me.
I have a strange issue which I don't really understand.
I have two views, one should have a black title and the other should have a white title.
The issue that I am experiencing is that I can set the color ONCE and not change it back.
So when I go to the view that has the white title from the view with the black title and then go back, the title does not change back to black.
code for white title in viewWillAppear:
self.navigationController?.navigationBar.barStyle = .black
self.navigationController?.navigationBar.tintColor = .white
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.white]
code for black title in viewWillAppear:
self.navigationController?.navigationBar.isHidden = false
self.navigationController?.navigationBar.barStyle = .default
self.navigationController?.navigationBar.tintColor = UIColor.blue
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.black]
Why does it not change back, when I am clearly setting a new color?
EDIT: adding the complete code
Black title view:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.navigationBar.isHidden = false
self.navigationController?.navigationBar.barStyle = .default
self.navigationController?.navigationBar.tintColor = hexStringToUIColor(hex: "4CAF50")
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.black]
self.navigationItem.title = listData.name
clearStatusBarColor()
let editButton = UIBarButtonItem(title: "Edit", style: .plain, target: self, action: #selector(tapToEdit))
let sortImg = UIImage(named: "sort")
sortingButton = UIBarButtonItem(image: sortImg, style: .plain, target: self, action: #selector(tapToSort))
self.navigationItem.rightBarButtonItems = [sortingButton!, editButton]
self.navigationController?.navigationBar.setBackgroundImage(nil, for: UIBarMetrics.default)
self.navigationController?.navigationBar.shadowImage = nil
// get updated Data
if User.active.hasListUpdated {
// return with new gameEntries -> Update
listData = User.active.allLists![listDataIndex] // To keep upToDate data!
listEntries = listData.list_entries!
gameEntries = listEntries.compactMap({ (entry: ListEntry) -> GameEntry in
return GameEntry(game: entry.game, platform: nil, platform_id: entry.platform, rating: Int(entry.rating ?? 0), review: nil, notes: entry.description)
})
listTable.reloadData()
}
// Sorting
if hasSortChanged {
hasSortChanged = false
sortList(sort: sortingOption, order: sortingOrder)
}
}
White title view:
override func viewWillAppear(_ animated: Bool) {
if !isPreviewing {
self.navigationController?.navigationBar.isHidden = false
self.navigationController?.navigationBar.barStyle = .black
self.navigationController?.navigationBar.tintColor = .white
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.white]
// MARK: Clear StatusBar
clearStatusBarColor()
if transparentNav {
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for:UIBarMetrics.default)
self.navigationController?.navigationBar.shadowImage = UIImage()
self.title = nil
} else {
self.navigationController?.navigationBar.setBackgroundImage(nil, for: UIBarMetrics.default)
self.navigationController?.navigationBar.shadowImage = nil
self.title = game.name!
}
}
// MARK: NavigationBar
let button = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(showOptions))
self.navigationItem.rightBarButtonItem = button
// Check if game should have new review or rating
if User.active.hasMainScreenUpdated {
// Update rating
updateUserRating()
// update review
updateUserReviewStatus()
}
// Update lists!
if User.active.hasListUpdated {
updateListsStatus()
}
}
If you are changing the nav bar colors in different view controllers, I recommend you to have a subclass of UIViewController and handle the navbar changes through that. Here's an example for your case.
class CustomUIViewController: UIViewController {
override func didMove(toParentViewController parent: UIViewController?) {
super.didMove(toParentViewController: parent)
if parent == nil {
if SettingsManager.LastBarColor == .default {
self.setLightBars()
}
else {
self.setDarkBars()
}
}
}
func setDarkBars() {
SettingsManager.LastBarColor = .lightContent
UIApplication.shared.statusBarStyle = UIStatusBarStyle.lightContent
tabBarController?.tabBar.tintColor = UIColor.white
navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.white]
}
func setLightBars() {
SettingsManager.LastBarColor = .default
UIApplication.shared.statusBarStyle = UIStatusBarStyle.default
tabBarController?.tabBar.tintColor = UIColor.Black
navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor:UIColor.Black]
navigationController?.navigationBar.barTintColor = UIColor.white
navigationItem.titleView?.tintColor = UIColor.Black
}
}
class SettingsManager {
class var LastBarColor: UIStatusBarStyle = .default
}
And in your view controller use CustomUIViewController, call setDarkBars() or setLightBars() in your viewWillAppear() function.
You can use a custom UINavigationController class then override pushViewController function to set what you need on the navigationBar.
The viewWillAppear method has a lot of code here.
class MyNavigationViewController: UINavigationController {
override func pushViewController(_ viewController: UIViewController, animated: Bool) {
super.pushViewController(viewController, animated: animated)
self.updateForVC(viewController: viewController)
}
func updateForVC(viewController: UIViewController) {
//DO WHATEVER YOU WHANT HERE, title, img, etc
var color = UIColor.black
if viewController.isKind(of: MyClass.self) {
color = UIColor.white
}
self.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor: color]
}
}
Try pushViewController to navigate,It is working for me
if let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SecondViewController") as? SecondViewController {
if let navigator = self.navigationController {
navigator.pushViewController(viewController, animated: true)
viewController.title = ""
}
}
I have a custom tab Bar where i add a button in the middle:
class CustomTabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
setupMiddleButton()
}
func setupMiddleButton() {
let numberOfItems = CGFloat(tabBar.items!.count)
let tabBarItemSize = CGSize(width: tabBar.frame.width / numberOfItems, height: tabBar.frame.height)
menuButton.frame = CGRect(x: 0, y: 0, width: tabBarItemSize.width, height: tabBar.frame.size.height)
var menuButtonFrame = menuButton.frame
menuButtonFrame.origin.y = self.view.bounds.height - menuButtonFrame.height - self.view.safeAreaInsets.bottom
menuButtonFrame.origin.x = self.view.bounds.width/2 - menuButtonFrame.size.width/2
menuButton.frame = menuButtonFrame
menuButton.backgroundColor = UIColor.clear
menuButton.addTarget(self, action: #selector(menuButtonAction), for: UIControlEvents.touchUpInside)
self.view.addSubview(menuButton)
self.view.layoutIfNeeded()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
menuButton.frame.origin.y = self.view.bounds.height - menuButton.frame.height - self.view.safeAreaInsets.bottom
}
}
This bar is shown in multiple controller.
However i have a specific controller where i'd like the tab bar to be hidden.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.tabBarController?.tabBar.isHidden = true
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.tabBarController?.tabBar.isHidden = false
}
This code works fine and the bar is actually hidden.
However If i click in the middle (where the menuButton is added) the button action is called (a segue is performed).
How can I disable the button when hiding the Tab bar?
Thank you for the help!
--------------UPDATE Solution
I am not sure this is the best solution because i'm new to swift, but it seems to work...
in my CustomTabBarController I have added to function:
func hideTabBar() {
self.tabBar.isHidden = true
self.menuButton.isHidden = true
}
func showTabBar() {
self.tabBar.isHidden = false
self.menuButton.isHidden = false
}
the whenever i need to hide/display it i call this functions.
In my case in the controller where i'd like to hide it i do so:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let tabBar = self.tabBarController as! FishBookTabBarController
tabBar.hideTabBar()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
let tabBar = self.tabBarController as! FishBookTabBarController
tabBar.showTabBar()
}
You are adding your button to self.view, so it is not "part of" your tab bar.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.tabBarController?.tabBar.isHidden = true
self.menuButton.isHidden = true
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.tabBarController?.tabBar.isHidden = false
self.menuButton.isHidden = false
}
That should do it.