I'm trying to go from a ViewController1 to a ViewController2 by changing the selectedIndex of the tabBarController.
In ViewController1:
func action() {
_ = self.tabBarController?.selectedIndex = 4
}
In ViewController2:
class ViewController2: UIViewController {
var isOnInfo = true
}
My problem is pretty simple. I would like to change the value of isOnInfo in the action() function.
Is it possible?
Another way to do that would be to create a global var, but if I can avoid that it would be better.
Thank you for you answers.
I can recommend you to move your changing tabs logic in Tab bar controller.
Make your own class TabBarController(subclass of UITabBarController), set it as custom class of your tab bar controller at the storyBoard and move the function action() there.
import UIKit
class TabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
}
func action(isOnInfo: Bool) {
selectedIndex = 4
if let viewControllers = self.viewControllers,
let viewController2 = viewControllers[selectedIndex] as? ViewController2 {
viewController2.isOnInfo = isOnInfo
}
}
}
Then in viewController1:
if let tabBarController = self.tabBarController as? TabBarController {
tabBarController.action(isOnInfo: false)
}
You can get object of viewcontroller at selected index in tabbarcontroller. once you have it, you can modify any public property.
func action() {
_ = self.tabBarController?.selectedIndex = 4
if let vc2 = self.tabBarController?.viewControllers![4] as?
ViewController2
{
vc2.isOnInfo = true
}
}
Related
I have three viewControllers and two of them connected to a tabBarController. So app should show one of the two vc’s depending Bool value when tapping on tabBar item here is my storyboard
import UIKit
class TabBarController: UITabBarController, UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
let userLoggedIn: Bool!
if tabBarController.selectedIndex == 1{
if userLoggedIn == true{
// show firstVC
}else{
// show secondVC
}
}
}
}
You can use childViewController with the parent is ViewController fromStoryboard.
override func viewDidLoad() {
super.viewDidLoad()
///add two ChildVC here, hide 1 ifneeded
}
When click to this tab you check userLoggedIn.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if userLoggedIn == true {
/// show first childVC
/// hide second childVC
} else {
/// hide first childVC
/// show second childVC
}
}
You can check demo: Demo
Simply add .overCurrentContext to modalPresentationStyle in your viewDidLoad like this.
let newVC = self.storyboard?.instantiateViewController(withIdentifier:"secondVC")
newVC?.modalPresentationStyle = .overCurrentContext
self.present(newVC!, animated: false, completion: nil)
Simply set the viewController list when the userLoggedIn variable is modified (assuming userLoggedIn is TabBarCOntroller instance variable) :
class TabBarC: UITabBarController {
#IBOutlet var firstVC : FirstViewController!
#IBOutlet var secondVC : SecondViewController!
#IBOutlet var thirdVC : ThirdViewController!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
for vc in self.viewControllers! {
if let fv = vc as? FirstViewController {
firstVC = fv
} else if let fv = vc as? SecondViewController {
secondVC = fv
} else if let fv = vc as? ThirdViewController {
thirdVC = fv
}
}
}
var userLoggedIn : Bool = false {
didSet {
if userLoggedIn {
self.viewControllers = [firstVC, thirdVC]
} else {
self.viewControllers = [secondVC, thirdVC]
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self. userLoggedIn = false
}
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
if item.tag == 3 { // For purpose of test i set tag for 3 VC to 1 for firsttVC, 2 for secondVC, 3 for thirdVC
// for test : change login value each time thirdVC is selected
userLoggedIn = ! userLoggedIn
}
}
So each time from anywhere in your code you setup userLoggedIn, the tabor show the wanted tab bar items.
The 3 VC are added to the tabbar in the stpryboard.
When selecting thirdVC, the first tab bar item changes between one and two
I have UIViewController and how I can to convert UIViewController to Class.swift. Class is initialized...
MainController.staticInstance.viewControllers?[1] as! Destination
MainController is class which extending UITabBarController. I want to get child controller from UITabBar and convert it to Class which parent.
Clearly example:
class MainController: UITabBarController {
override func viewDidLoad() {
(self.viewControllers?[1] as! Destination).itsMyFunction();
}
}
MAXIMUM DETAIL:
1 class
class First: UIViewController {
func itsMyFunction() {
print("Hello world!")
}
}
this is Class I attach to class in STORYBOARD!
2 class
class MainController: UITabBarController {
func override viewDidLoad() {
// Here I set index UITabBar ITEM which attach to MAIN UiTabBarController
self.selectedIndex = 0
// NOW I want to get INSTANCE CLASS First
(self.viewControllers?[1] as! First).itsMyFunction();
}
}
Can you please follow this setup example?
class TabBarViewController: UITabBarController {
let firstVC = First()
let secondVC = SecondViewController()
override func viewDidLoad() {
super.viewDidLoad()
firstVC.tabBarItem = UITabBarItem(tabBarSystemItem: .search, tag: 0)
secondVC.tabBarItem = UITabBarItem(tabBarSystemItem: .more, tag: 1)
let tabBarList = [firstVC, secondVC]
viewControllers = tabBarList
if let destination = viewControllers?.first as? First {
destination.itsMyFunction()
}
}
}
It seems that you fail to get the Class instance of the controller because your viewControllers array is empty based on the code that you posted. Let me know if it worked.
That way you get a crash if the type is something different. Try to avoid using ! whenever you can.
Use a weak cast and evaluate the unwrapped type if its yours.
if let destination = destMainController.staticInstance.viewControllers?.first as? Destination {
destination.itsMyFunction()
}
I try to use delegate to reset my ViewControllerA (HomePage) property "type" value when I logout.
But I set breakpoint and my delegate function work success.
When I login again, and print my property "type" in ViewWillAppear. It's also cache old value before I logout.
Please tell me what's wrong with me.
Thanks.
class ViewControllerA: UIViewController, CustomDelegate {
enum Type: Int {
case book = 0
case pen
}
var tmpType: Type?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
printBBLog("tmpType: \(tmpType)") //before I logout the value is "pen",and I login again the value is "pen".
}
func clearType() {
printBBLog("clear")
self.tmpType = nil
printBBLog("\(self.tmpType)")
}
#objc func bookBtnClicked(sender: UIButton) {
self.tmpType = .book
}
#objc func penBtnClicked(sender: UIButton) {
self.tmpType = .pen
}
}
class ViewControllerB: UIViewController {
var delegate: CustomDelegate?
func doLogout() {
let vc = ViewControllerA()
self.delegate = vc
self.delegate?.clearType()
}
}
You are creating a new instance of your ViewControllerA. since you are using the UITabBarController you can access you ViewControllerA from your ViewControllerB and assign the delegate. after that you will get your desired result. for reference please check below code.
class ViewControllerB: UIViewController {
var delegate: CustomDelegate?
func doLogout() {
let viewControllers = self.tabBarController?.viewControllers
if let vc1 = viewControllers[0] as? ViewControllerA {
self.delegate = vc1
self.delegate?.clearType()
}
}
}
if you are using UINavigationController inside the UITabBarcontroller then use:
if let vc1 = ((self.tabBarController?.viewControllers?[0] as? UINavigationController)?.viewControllers[0] as? ViewControllerA)
I'm using a UITabBarController and I would like to use a button in a view to move to the next view without having to click on the bar.
How could I do that programmatically ?
class PlayTableBarViewController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
}
func nextView() {
print(self.viewControllers!)
self.selectedViewController = self.viewControllers![self.selectedIndex + 1]
self.show(self.selectedViewController!, sender: nil)
}
}
class StartVC: UIViewController {
private var _fatherVC: PlayTableBarViewController?
var fatherVC: PlayTableBarViewController {
if _fatherVC == nil {
_fatherVC = self.storyboard?.instantiateViewController(withIdentifier: "playViewController") as? PlayTableBarViewController
}
return _fatherVC!
}
#IBAction func backToGame(_ sender: UIButton) {
fatherVC.nextView()
}
}
Use selectedIndex property of UITabBarController (until you want to have More section in your UITabBar.
From:
https://developer.apple.com/documentation/uikit/uitabbarcontroller/1621171-selectedindex
Setting this property changes the selected view controller to the one
at the designated index in the viewControllers array. To select the
More navigation controller itself, you must change the value of the
selectedViewController property instead.
class PlayTableBarViewController: UITabBarController {
func nextView() {
self.selectedIndex = self.selectedIndex + 1
}
}
I found the error where I initialize _fatherVC. This:
_self.storyboard?.instantiateViewController(withIdentifier: "playViewController")
as? PlayTableBarViewController_
should be:
_fatherVC = self.tabBarController as? PlayTableBarViewController
Now it's working perfectly.
I need to send some data back from secondView to First View by popView.
How can i send back the data by popViewControllerAnimated?
Thanks!
You can pass data back using delegate
Create protocol in ChildViewController
Create delegate variable in ChildViewController
Extend ChildViewController protocol in MainViewController
Give reference to ChildViewController of MainViewController when navigate
Define delegate Method in MainViewController
Then you can call delegate method from ChildViewController
Example
In ChildViewController: Write code below...
protocol ChildViewControllerDelegate
{
func childViewControllerResponse(parameter)
}
class ChildViewController:UIViewController
{
var delegate: ChildViewControllerDelegate?
....
}
In MainViewController
// extend `delegate`
class MainViewController:UIViewController,ChildViewControllerDelegate
{
// Define Delegate Method
func childViewControllerResponse(parameter)
{
.... // self.parameter = parameter
}
}
There are two options:
A) with Segue
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
let goNext = segue.destinationViewController as ChildViewController
goNext.delegate = self
}
B) without Segue
let goNext = storyboard?.instantiateViewControllerWithIdentifier("childView") as ChildViewController
goNext.delegate = self
self.navigationController?.pushViewController(goNext, animated: true)
Method Call
self.delegate?.childViewControllerResponse(parameter)
If you want to send data by popping, you'd do something like:
func goToFirstViewController() {
let a = self.navigationController.viewControllers[0] as A
a.data = "data"
self.navigationController.popToRootViewControllerAnimated(true)
}
Extending Dheeraj's answer in case your ViewController is not first VC in the stack, here is the solution:
func popViewController() {
guard let myVC = self.navigationController?.viewControllers.first({ $0 is MyViewController }) else { return }
myVC.data = "data"
self.navigationController?.popViewController(animated: true)
}
However, this solution will break if you have 2 or more than 2 MyViewController in the stack. So, use wisely.
Answer given here is a little complex, quite simple to just use UINavigationControllerDelegate
class FirstNavigationController: UIViewController {
var value: String?
}
class SecondNavigationController: UIViewController, UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
guard let vc = navigationController.topViewController as? FirstNavigationController else { return }
vc.value = "Hello again"
}
}
self.navigationController?.popViewController(animated: true)
let vc = self.navigationController?.viewControllers.last as! MainViewController
vc.textfield.text = "test"
this popviewcontroller solutions