Open two controller A & B on one tab item in swift - ios

I have a problem, I want to open two view Controllers on single tab from to different way.
Like:
Login Screen --> Home Screen --> On home screen two button A & B
1 When click on the button A, open A controller on tab controller tab1
2 When click on the button B, open B controller on tab controller tab1
I have 5 tab in tab controller.
Please help me for that issue.
Please refer attached screen for more help.
Thanks,

you can replace ViewController By using this
func tabBarController(tabBarController: UITabBarController, didSelectViewController viewController: UIViewController) -> Bool {
let selectIndex : NSInteger = (tabBarController.viewControllers?.index(of: viewController))!
if (selectIndex == 1) {
let vc = UIViewController() // your new Controller
var allviews = tabBarController.viewControllers
allviews?.remove(at: selectIndex)
allviews?.insert(vc, at: selectIndex)
tabBarController.setViewControllers(allviews, animated: true)
return false;
}
return true;
}

(Please add some more information to your question, or at least code to know what have you tried.)
By your question, It seems you need a Tab Bar Controller.
You use tab bar controller to organize your app into one or more distinct modes of operation. The view hierarchy of a tab bar controller is self contained. It is composed of views that the tab bar controller manages directly and views that are managed by content view controllers you provide. Each content view controller manages a distinct view hierarchy, and the tab bar controller coordinates the navigation between the view hierarchies.

Related

How to close multiple viewcontrollers in one time?

For my requirement, I have to go back to my rootviewcontroller (tabbar) but It have many page present on it.
example flow
my tabbar (have 4 tabs each tab has own navigation ) -> push(vc1) -> present nav(vc2) -> push vc3 -> present nav(vc4)
If I want to close all viewcontroller ( vc1 - vc4 ) How to dismiss them by one function ?
You can use UIViewController.dismiss(animated:completion:) call on the base view controller that started presentation from tab bar (root level).
If you present several view controllers in succession, thus building a stack of presented view controllers, calling this method on a view controller lower in the stack dismisses its immediate child view controller and all view controllers above that child on the stack. When this happens, only the top-most view is dismissed in an animated fashion; any intermediate view controllers are simply removed from the stack. The top-most view is dismissed using its modal transition style, which may differ from the styles used by other view controllers lower in the stack.
Given this hierarchy
my tabbar (have 4 tabs each tab has own navigation ) -> push(vc1) -> present nav(vc2) -> push vc3 -> present nav(vc4)
You can walk back the presentation hierarchy like following -
let vc4Presenter = vc4.navigationController?.presentingViewController
let vc2NavCtrl = (vc4Presenter as? UINavigationController) ?? vc4Presenter?.navigationController
let vc2Presenter = vc2NavCtrl?.presentingViewController
let vc1NavCtrl = (vc2Presenter as? UINavigationController) ?? vc2Presenter?.navigationController
vc2Presenter?.dismiss(animated: true, completion: {
vc1NavCtrl?.popToRootViewController(animated: false)
})
Above is merely an example of how you can find the correct view controller instance to call dismiss on in the view hierarchy. This is definitely not well suited for dynamic number of presentation layers.
You can -
Write this in a recursive way (so that it keeps looking for presentingViewController until it finds nil for the root level).
Have a convenient reference to tab bar controller throughout the app and call dismiss on it's currently selected view controller (tab).
If you want go directly to first viewController:
self.popToRootViewController(animated: true)
If you want to see how it is going away one by one
#objc func buttonPressed() {
let viewControllers: [UIViewController] = self.viewControllers
for aViewController in viewControllers {
self.popViewController(animated: true)
}
self.popToRootViewController(animated: true)
}

Navigation bar won't show after pushing a view controller

I'm trying to move from a View Controller to another.
I worte this function to use when the user tap on a button to move to the new view controller:
#objc private func infoButtonTap(){
let navVC = UINavigationController()
navVC.addChild(AboutViewController())
self.navigationController?.pushViewController(AboutViewController(), animated: true)
}
The problem is that the new view controller is presented on the screen but I don't have a navigation bar and a back button to move back.
I do not use Storyboard as I want to learn coding the UI.
I tried few things I found here on Stackoverflow but none worked for me.
How can I set the new view controller to have a navigation bar with back button?
UINavigationController has a variable isNavigationBarHidden
#objc private func infoButtonTap(){
let navVC = UINavigationController()
navVC.addChild(AboutViewController())
self.navigationController?.isNavigationBarHidden = false
self.navigationController?.pushViewController(AboutViewController(), animated: true)
}
You need to push the view Controller. Try this
let aboutVC = AboutVC()
self.navigationController?.pushViewController(aboutVC, animated: true)
You don't need to write any code.
Select the Root Navigation Controller the will control the app. In the Inspector Bar, select Simulated Metrics ( The Third Selection from the Right in the Inspector) and Check the Box " Is Initial View Controller". Then connect the next View controller which will be in essence the Landing page for the app. Once you connect other View Controllers to that View controller via a button for instance ( Select the button, then press Control Key + Drag to View Controller, select Show) , you will see the navigation Bar with "Back" displayed. Once that's done, you can add other view controllers and connect them from the landing page view controller and the Navigation Bars will be displayed.
For navigation to be visible and of use in an app , first you need to set up a Navigation controller with a Root view controller i.e your first controller and from there you can use push method on your navigation controller object to push a controller on to the stack.
For eg
let navVC = UINavigationController.init(rootViewController: YourFirstViewControllerObject())
navVC.pushViewController(NewViewControllerObj(), animated: true)

Intercepting ios back button to send back to base view controller

We have a sequence of screens that navigate in order...
BaseViewController -> A -> B -> BaseViewController
Each screen uses NavigationController.PushViewController to go from...Base->A, A->B. So each subsequent screen is placed in the navigation stack.
So if you are on A and you click 'back', then it goes back one screen. This works well as it is controlled by the NavigationController.
However, when you are on screen B, 'back' should to back to the BaseViewController.
Instead it goes (as designed by Apple) back to A. Is there a way to intercept the 'back' button on B so we can instead use NavigationController.PopToViewController to send the user back to BaseViewController?
As #the4kman mentioned , we can create a custom button to replace the LeftBarButtonItem ,and handle the back event .
ViewDidLoad in B
this.NavigationItem.LeftBarButtonItem =
new UIBarButtonItem("back", UIBarButtonItemStyle.Plain, (sender,e) => {
UIViewController baseVC = NavigationController.ViewControllers[NavigationController.ViewControllers.Length - 3];
NavigationController.PopToViewController(baseVC, true);
});
As #J.C. Chaparro mentioned , remove A from stack .
ViewDidLoad in B
List<UIViewController> list = NavigationController.ViewControllers.ToList<UIViewController>();
list.RemoveAt(list.Count-2);
NavigationController.ViewControllers = list.ToArray();
You can do something like this in B's viewDidAppear function:
guard let navigationController = self.navigationController else {
return
}
navigationController.viewControllers.remove(at: navigationController.viewControllers.count - 2)
This will remove A from the stack, and allow you to go back to BaseViewController from B.
If I understand correctly you want to pop to root view controller from a certain top view controller. One way to do it would be to create a subclass of UINavigationController and override popViewController method where you would check what you have on top at the moment and decide to pop to root or not. Here's an example:
open class CustomNavigationController: UINavigationController {
override open func popViewController(animated: Bool) -> UIViewController? {
if topViewController is BViewController {
return popToRootViewController(animated: animated)?.last
} else {
return super.popViewController(animated: animated)
}
}
}
Approach:
Use child view controllers
Steps:
Create a view controller C which is a subclass of Base
Add A as a child view controller to C
Create a view controller D which is a subclass of Base
Add B as a child view controller to D
Push C to D
Thanks for all the answers. #Cole Xia put me on the right path for our scenario. His technique works, and the following works as well.
Here is the Xamarin code. The technique is to replace the current list of ViewControllers with a new one. Then when 'back' is hit on B, it goes right back to BaseViewController.
var viewControllers = new UIViewController[] { NavigationController.ViewControllers[0], new B() };
NavigationController.SetViewControllers(viewControllers, false);

Swift: How to segue between view controllers and use navigation bar to go backwards within a child view controller (XLPagerTabStrip)

I am currently implementing the XLPagerTabStrip (https://github.com/xmartlabs/XLPagerTabStrip) which effectively creates a tab bar at the top of the view controller. I want to be able to segue to a new view controller from one of the tabbed controllers and be able to use the navigation bar to move backwards (or a custom version of the navigation bar if this isn't possible).
XLPagerTabStrip provides the moveToViewController and moveToViewControllerAtIndex functions to navigate between child view controllers, but this method doesn't allow use of a navigation bar to go backwards.
Conceptually XLPagerTabStrip is a collection of view controllers declared and initialized during the XLPagerTabStrip model creation.
It has virtually no sense to use a UINavigationController if you already have all the viewcontrollers available.
You can create a global var previousIndex to store the previous viewController index and allow users to go back by using canonical methods:
func moveToViewControllerAtIndex(index: Int)
func moveToViewControllerAtIndex(index: Int, animated: Bool)
func moveToViewController(viewController: UIViewController)
func moveToViewController(viewController: UIViewController, animated: Bool)
About a new viewController, suppose you have 4 viewControllers that built your container (XLPagerTabStrip) named for example z1, z2, z3 e z4.
You can embed to z4 a UINavigationController (so it have the z4 controller as rootViewController) and start to push or pop your external views. When you want to return to your z4 you can do popToRootViewControllerAnimated to your UINavigationController
When you are go back to z4 , here you can handle your global var previousIndex to moving inside XLPagerTabStrip.
I'm not familiar with XLPagerTabStrip, but I had a similar problem recently and the solution was to use an unwind segue to go back to the previous view controller. It's pretty trivial to implement so probably worth a try.
To navigate back to your previous view tab controller, you had initially navigated from;
Embed your new view controller, from which you wish to navigate
away from in a navigation bar
Connect it's Navigation Bar Button to the Parent view containing the
tab bar by dragging a segue between the 2 views
Create a global variable in App delegate to store current index
which you will use in the Parent view to determine what tab view
controller to be shown
var previousIndex: Int = 0 //0 being a random tab index I have chosen
In your new view controller's (the one you wish to segue from)
viewdidload function, create an instance of your global variable as
shown below and assign a value to represent a representative index
of the child tab bar view controller which houses it.
//Global variable instance to set tab index on segue
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.previousIndex = 2
You can write this for as many child-tab connected views as you wish, remembering to set the appropriate child-tab index you wish to segue back to
Now, create a class property to reference your global variable and a function in your Parent view as shown below
let appDelegatefetch = UIApplication.shared.delegate as! AppDelegate
The function
func moveToViewControllerAtIndex(){
if (appDelegatefetch.previousIndex == 1){
self.moveToViewControllerAtIndex((self.appDelegatefetch.previousIndex), animated: false)
} else if (appDelegatefetch.previousIndex == 2){
self.moveToViewControllerAtIndex((self.appDelegatefetch.previousIndex), animated: false)
}
}
You may now call this function in the Parent View Controller's viewDidLoad, as shown below.
moveToViewControllerAtIndex()
Run your project and that's it.

iOS: Navigation Bar not showing up on manual segue

I have the following setup
-> Navigation Controller -> View Controller A -> View Controller B
B has some left and right navigation items which show up in this sequence
I have another flow where
-> Navigation Controller -> View Controller A -> View Controller C -> View Controller B
In ViewController C, when a save button is sliced, I manually trigger the segue to show View B. But, in this scenario, the navigation bar does not show up.
If I embed controller B in a navigation controller, then in the prepareFor Segue of Controller C, I cannot refer this as the destination. How do I fix this?
I am putting in some screen shots of the settings below:
This is the nav bar in A
The segue from A->B. This is triggered by selecting a row in a table View
This is how the nav bar in B looks when triggered from A
The segue from A->C
This is the nav bar in C
The segue from C->B
From C to B, I am triggering the segue as below:
dispatch_async(dispatch_get_main_queue(), {
self.performSegueWithIdentifier("SegueGroupView", sender: self)
})
On this trigger, the nav bar in B is not appearing

Resources