EDIT - Simplified version:
If I go from a ViewController
to a Tab Bar Controller
via a Button
, how do I get back to the ViewController
? How do I (can I?) add a button to the Tab Bar to do so?
(the top half of the below image along with the Tab Bar menu shown below that)
I want to navigate between a View Controller
and different Tab Bar Controllers
.
Ideally, this would be done with a "Main Menu" button on each of the Tab Bar Controllers
.
So in this example, each of the Tab Bar Controllers
would have three buttons like this instead of the two shown above.
CodePudding user response:
- Create three buttons on each tab controller (name one Main Menu)- make the main menu controller blank
- Create (and name) relationship segues between the Main Menu blank view controllers (by holding the control button and dragging a relationship between the Main Menu controllers and the main VC, and do present modally, over view controller)
- Link both Main Menu tabs to a standard Cocoapods storyboard file, and on view did load, perform the segue like so:
self.performSegue(withIdentifier: "name", sender: self)
CodePudding user response:
I have a couple of options for you to accomplish this.
The simplest and perhaps the right way would be embed your main menu inside a UINavigationController
and then push
to either of your UITabBarControllers
That would give you a back button for free to your main menu on the navigation bar. I recommend this approach.
However, if you don't want to / cannot use a UINavigationController
and / or want to get this functionality by having an extra main menu button on your tab bar, here is a workaround:
- Subclass the UITabBarController
- Override the
viewControllers
property and observe when it gets set - Once it is set, add an extra view controller at the beginning
- Observe when you tap on the first tab and go back to the main menu view controller
To get this working, here is a small demo I created.
First, I created 4 random view controllers to serve as the view controllers inside my tab bar controller
fileprivate class PurpleVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .purple
title = "Purple"
}
}
fileprivate class WhiteVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
title = "White"
}
}
fileprivate class RedVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .red
title = "Red"
}
}
fileprivate class YellowVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .yellow
title = "Yellow"
}
}
Then I subclassed the UITabBarController to get my custom functionality
class CustomTabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
// This is needed to observe which tab was tapped
delegate = self
}
// This is needed to prevent a loop when adding the dummy view controller
private var isConfiguringTabs = false
override var viewControllers: [UIViewController]? {
didSet {
addMenuVC()
isConfiguringTabs = false
}
}
private func addMenuVC() {
if !isConfiguringTabs {
isConfiguringTabs = true
let menuViewController = UIViewController()
if let currentVC = viewControllers?.first {
menuViewController.view.backgroundColor
= currentVC.view.backgroundColor
}
menuViewController.title = "Main Menu"
// Add a dummy view controller so that we get the
// first tab
viewControllers?.insert(menuViewController, at: 0)
}
}
}
extension CustomTabBarController: UITabBarControllerDelegate {
func tabBarController(_ tabBarController: UITabBarController,
didSelect viewController: UIViewController) {
// If you select the first tab, go back to the main menu
if tabBarController.selectedIndex == 0 {
dismiss(animated: true, completion: nil)
return
}
// Otherwise just change the bg color of the first view controller
// to the current view controller's background which gives it a
// better transition when going back to the main menu
if let menuVC = viewControllers?.first,
let currentVC = viewControllers?[tabBarController.selectedIndex] {
menuVC.view.backgroundColor = currentVC.view.backgroundColor
}
}
}
Then I create the main menu view controller and make use of this custom tab bar controller when tapping on a button
class MainMenuVC: UIViewController {
let buttonA = UIButton(type: .system)
let buttonB = UIButton(type: .system)
override func viewDidLoad() {
super.viewDidLoad()
title = "Main Menu"
view.backgroundColor = .white
configureButtonA()
configureButtonB()
}
private func configureButtonA() {
buttonA.translatesAutoresizingMaskIntoConstraints = false
buttonA.setTitle("Button A", for: .normal)
buttonA.setTitleColor(.white, for: .normal)
buttonA.backgroundColor = .systemBlue
buttonA.addTarget(self, action: #selector(buttonATapped),
for: .touchUpInside)
view.addSubview(buttonA)
view.addConstraints([
buttonA.centerXAnchor.constraint(equalTo: view.centerXAnchor),
buttonA.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
buttonA.widthAnchor.constraint(equalToConstant: 100),
buttonA.heightAnchor.constraint(equalToConstant: 100)
])
}
private func configureButtonB() {
buttonB.translatesAutoresizingMaskIntoConstraints = false
buttonB.setTitle("Button B", for: .normal)
buttonB.setTitleColor(.white, for: .normal)
buttonB.backgroundColor = .red
buttonB.addTarget(self, action: #selector(buttonBTapped),
for: .touchUpInside)
view.addSubview(buttonB)
view.addConstraints([
buttonB.centerXAnchor.constraint(equalTo: view.centerXAnchor),
buttonB.topAnchor.constraint(equalTo: buttonA.bottomAnchor,
constant: 40),
buttonB.widthAnchor.constraint(equalToConstant: 100),
buttonB.heightAnchor.constraint(equalToConstant: 100)
])
}
private func presentTabController(with viewControllers: [UIViewController]) {
let customTabController = CustomTabBarController()
customTabController.viewControllers = viewControllers
customTabController.modalPresentationStyle = .fullScreen
present(customTabController, animated: true, completion: nil)
}
@objc
private func buttonATapped() {
presentTabController(with: [WhiteVC(), PurpleVC()])
}
@objc
private func buttonBTapped() {
presentTabController(with: [YellowVC(), RedVC()])
}
}
And finally, since I don't use storyboards I instantiate the main menu view controller from the scene delegate which you don't need to do
So this gives me the following experience with an additional tab in the beginning that goes back to the main menu when tapped