I currently have a UITabBarController with two tabs, one of which leads to a storyboard that has several view controllers within it. The problem occurs when I traverse away from the storyboard tab and then come back to it and I find myself at the view controller that I left off. How can I ensure that every time I come back to the tab with the storyboard, I start at the initial view controller?
Try this in Swift:
override func viewWillAppear(animated: Bool) {
if(tabBarController?.selectedIndex == 1){ //The second tab index
tabBarController?.selectedIndex = 0
}
}
Related
Hi I am new to Swift and am trying to build an app with multiple Views..
My first View(initial view) is embedded in navigation controller.
My Second View is embedded in Tab Bar Controller
My Third View is again embedded in a Navigation Controller.
The problem is that on my third view I see to navigation Controller with the top one taking me back to First View and the below one taking me to Second View.
Is it an incorrect way of doing this? I want to get rid of navigation bar that came from 1st view.
Thanks in anticipation.
PS : I had initially not attempted Navigation Bar on 3rd View.. but the problem was that I am also not able to map Bar Button Item and hence to embed the 3rd View too in a separate Navigation Controller
While it shows perfect in Xcode.. it shows 2 NavBar on the simulator
Not an elegant solution but still this can solve your problem. On your controller embed to UITabBarController where you have added Next Button. Add the below code on that controller class.
On ViewWillappear add show nav bar and on viewDidDisappear hide nav bar as shown in below code
ON viewWillAppear:
override func viewWillAppear(_ animated: Bool) {
self.navigationController.navigationBar.isHidden = false
}
ON viewDidDisappear:
override func viewDidDisappear(_ animated: Bool) {
self.navigationController.navigationBar.isHidden = true
}
I have a viewController that is embedded in a nav controller. This nav controller is then embedded in a tab bar controller.
I have another viewController that is not supposed to be accessible from the tabBarController. It should only be accessible from the first viewController using a button. From the secondViewController, I made a UIBarButtonItem to move back to the original view. From the first view to the second view and vice versa, I used a Storyboard reference to move to and from from the views.
However, when I move from the first view to the second view, the tab bar controller disappears (like it should). When I move back to the first view, the tab bar controller disappears and I cannot move between tabs anymore.
I tried including:
self.hidesBottomBarWhenPushed = false
on the first view and
self.hidesBottomBarWhenPushed = true
on the second view
and nothing seems to work. The tab bar controller disappears every time i move from the second view to the first view.
You are following a wrong hierarchy. You are actually using seagues to go back and forth. This creates a new instance every time you try to come back to the first controller.
Let's make it clear:
You need to follow the below approach:
1 You have two controllers A and B.
2 Use self.hidesBottomBarWhenPushed = true in viewDidLoad or viewWillAppear of controller A.
3 Controller A is embedded in a navigation controller which is further embedded in a UITabBarController.
Tapping a button in controller A, you need to push to controller B. So you can use segue for this or you can do it programatically like:
let controllerB = B()
A.navigationController?.pushViewController(controllerB, animated: true)
4 Go Back to Controller A on the tap UIBarButtonItem. So your code in the action of UIBarButtonItem should be something like:
self.navigationController?.popViewController(animated: true)
Remember you should not should segue to go back to the previous controller.
you should use
override func viewWillDisappear(_ animated: Bool) {
self.tabBarController?.tabBar.isHidden = false
}
in that controller where the back button is placed, I am using the exact scenario in one of the my app.
In iOS 10, I could determine the list of navigation bar buttons I want to appear in viewDidLoad, and they would appear in the navigation bar as the view controller transitioned in.
In iOS 11, I can no longer do this. Whatever navigation bar buttons were set in interface builder are displayed as the view controller transitions in, and my custom list of buttons are not displayed until after the view finishes sliding in. Updating the buttons in viewWillAppear does not help.
Is this simply a bug in iOS 11, or is there something else I should be doing? Is there a workaround so I can continue to display buttons while the screen loads?
In the following example, I have set a button "Default Button" in the storyboard, and override it with an "Edit" button in viewDidLoad. The project is available on Github.
iOS 10
iOS 11
It looks like the issue is that navigation bar icons displayed during the transition appear to be fixed when the view controller is passed off to the navigation controller. By the time that viewDidLoad is called, the icons have already been fixed.
In order to fix this, we need to update the navigation bar icons on the view controller's navigationItem before the view controller is pushed onto the navigation controller stack.
One way to do this would be to setup the navigation bar icons in awakeFromNib. This is what #Joe's answer was effectively doing, because apparently viewDidLoad is called from awakeFromNib when isViewLoaded is true during awakeFromNib.
However, doing this in awakeFromNib prevents you from taking into account any properties set on the view controller in prepareForSegue. So another option (and the one that I am using) is to force the entire view to load in prepareForSegue by adding the line _ = controller.view after setting any desired properties.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showDetail" {
if let indexPath = tableView.indexPathForSelectedRow {
let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
...
_ = controller.view
}
}
}
Move your Edit barButton code from viewDidLoad to isViewLoaded method as below.
override var isViewLoaded: Bool {
self.navigationItem.rightBarButtonItem = self.editButtonItem
return true
}
Output:
Note: Above code will fix the transition delay issue. Really, don't have much to explain why this happening. I experienced similar issue in iOS 10 as well NavigationBar delay updating barTintColor iOS10. It could be another bug in iOS11.
PS:
After reading Apple Doc about isViewLoaded and comparing other view loading methods. Its all about loading memory upon view loads.
You don't really need to move you barButton code at all.Just implement the isViewLoaded method and return to true as below:
override var isViewLoaded: Bool { return true}
In my storyboard, I have setup a navigation controller points to my MainVC, and it works just fine.
And now, I'm trying to add another view called "HelpVC", and I created one in the storyboard. It automatically shows the navigation bar on the top.
(MainVC segues to HelpVC)
However, I did everything else in code.
I had initWithView in the HelpVC which draws out the interface, BUT the navigation bar does not show up, so I can't go back to that previous view controller.
How do I make sure that the navigation bar shows up and works just like other view controllers? (segue back to the last view?)
It is not very clear from the post, but as I understood, you may want to try:
override func viewWillAppear(_ animated: Bool){
super.viewWillAppear(animated)
self.navigationController?.isNavigationBarHidden = false
}
I have TabBar with 2 tabs. At some point, from either of the 2 tabs, I want to add a view that is visible on both tab views but behind the TabBar.
So I thought, insert a subview into the TabBarController but below the TabBar.
This works fine in principle and I have the view behind the TabBar but now covering my 2 tabs as I wanted. However, it doesn't actually load. Just its background loads and only viewDidLoad() is called, not viewWillAppear() or any others.
I have also tried calling addChildViewController(myVC) on the TabBarController which has no effect, and also manually calling viewWillAppear() on the view controller I add which also has no effect (and I'm also dubious about whether manually calling viewWillAppear() is permitted or not?).
Is what I'm trying to do possible? What am I missing? Or should I be attempting this some other way?
For some reason, when inserting a subview into a UITabBarController behind it's UITabBar, although the view is visible to the user, the system itself seems to think it is not and so although viewDidLoad() is called, viewDidAppear() and subsequent methods are not.
However, adding a subview above the UITabBar seems to work fine. So I solved this by adding my own new UITabBar as a subview to the UITabBarController (set up basically exactly as the default one would be) and then removing the UITabBarController's default UITabBar.
Then when later inserting my view into the UITabBarController, I insert it as I was doing originally but instead below/behind my custom UITabBar and it seems to load fine.
There is no need to remove and recreate the tabBar. What you need to do is after you insert your custom view, you can then bring the tabBar to the front again.
//bring the tabBar to the front after inserting new view
self.view.bringSubview(toFront: self.tabBar)
This would be a good way:
Add the function below and call it in viewDidLoad of your initial VC. It unwraps your tab bar controller instance (which is optional), and then inserts the view you always want visible just below the tab bar.
private func setupAlwaysVisibleView() {
guard let tabBarController = self.tabBarController else { return }
tabBarController.view.insertSubview(alwaysVisibleView, belowSubview: tabBarController.tabBar)
}
Avoid using optionals for tabBarController or removing current tabBar. Simple add your view below tabBar view. Swift 5, XCode 11.
class TabBarController: UITabBarController {
#IBOutlet var instructionsView: UIView!
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.view.insertSubview(instructionsView, belowSubview: self.tabBar)
}
}
you can also do this inside the init() method for your UITabViewController:
view.insertSubview(alwaysVisibleView, belowSubview: self.tabBar)
no need to dispatch to another method if you are using a subclass of UITabViewController.