NavigationBar not showing on TableviewController in swift - swift

I have a CollectionView running in my project and the collectionViewController connected to another tableview using custom segue as follows.
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
selectedMenuItem = indexPath.row
//Present new view controller
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main",bundle: nil)
var destViewController : UINavigationController
switch (indexPath.row) {
case 0:
destViewController = mainStoryboard.instantiateViewControllerWithIdentifier("NewTableView") as UINavigationController
break
default:
destViewController = mainStoryboard.instantiateViewControllerWithIdentifier("NewTableView") as UINavigationController
break
}
self.presentViewController(destViewController, animated: true, completion: nil)
}
above code populating my NewTableview successfully but the tableview missing navigation bar completely.
so far my tries as follow...
i embedded new navigationController to collectionView results remain unchanged.
i embedded new navigationController to NewTableView results remain unchanged.
i tried unwind segue method using custom navigation button action method.so i insert the navigation bar item and button to the view and Method works,but it works strangly when navigation bar button pressed it takes me to my main collection view controller thats what i what.but i have another back button appears in collection view rowindex item name on it.when i pressed the button it take me back to the NewTableView its like looping through.
i don't know what i am missing (any delegate method).and i noticed the newTableView data loading from the bottom with animation...
i wondering is there any way to put a navigation programmatically with back button behaviour...
Thanks in Advance.....

You'll have to instantiate the navigation controller, not the actual view controller from your storyboard. So instead of instantiating NewTableView (the view controller you want embedded in the navigation controller), you should add an identifier to your UINavigationController so that it will be instantiated instead of the view controller itself.
Just imagine that you reuse the NewTableView controller which does not require a navigation controller as its root, how would iOS be aware of that ? So add an identifier to your hosting UINavigationController and instantiate that. The navigation controller has a root dependency on the rootViewController which will be shown by default, so you only need to display the UINavigationController and the NewTableView controller will be shown based on the dependency it has with the navigation controller.

Related

How to do popViewController from another class?

My app has a TabBarController. Each tabBarItem relates to a ViewController embedded in a NavigationController.
When in first tabBarItem and selecting another tabBarItem I want to do some stuff before moving to the selected ViewController. Therefore I created a class for my tabBarController and made it UITabBarControllerDelegate.
What I want to do is present an alert with two buttons; button A cancels the move to the selected viewController and button B lets the move happen.
My problem is that when button B is pressed, I want to popToRootViewController. I gave the navigationController a storyboardID and tried to instantiate it like shown below.
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if let alert = self.storyboard?.instantiateViewController(withIdentifier: "ActiveSessionWarningAlert") as? ActiveSessionWarningAlert {
alert.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
alert.modalTransitionStyle = UIModalTransitionStyle.flipHorizontal
let alertWasDismissed: (Bool) -> Void = { userWantsToMoveToSelectedViewController in
if userWantsToMoveToSelectedViewController {
if let navContr = self.storyboard?.instantiateViewController(withIdentifier: "firstNavContr") as? UINavigationController {
navContr.popToRootViewController(animated: true)
}
tabBarController.selectedViewController = viewController
}
}
alert.alertWasDismissed = alertWasDismissed
self.present(alert, animated: true, completion: nil)
}
return false
}
Everything works as expected, but the popToRootViewController doesn't seem to occur; when selecting the first tabBarItem again the same viewController that was 'active' when we left the item is still showing.
I checked so that the viewController I want to pop is actually in the navigation stack and that the navContr != nil.
What am I missing?
You don't say so, but I'm assuming that the alertWasDismissed closure you pass to your alert view controller gets invoked when the user dismisses the alert.
The problem with your closure is this bit:
if let navContr = self.storyboard?.instantiateViewController(withIdentifier: "firstNavContr") as? UINavigationController
Any time you call instantiateViewController(withIdentifier:), you are creating a brand new, never before seen instance of a view controller (a navigation controller in this case.) That navigation controller has nothing to do with the one that belongs to the current tab that you are trying to dismiss. It doesn't have anything in it's navigation stack other than the root view controller that is defined in the storyboard.
What you need to do is find the navigation controller of the current tab in your tab bar controller's tabBarController(_:shouldSelect:) method, and pass that navigation controller to your alertWasDismissed closure.
At the time the tabBarController(_:shouldSelect:) method is called, the tab bar controller's selectedViewController should contain the current view controller. Replace the line above with:
if let navContr = tabBarController.selectedViewController? as? UINavigationController {}
That should work.

Swift - Permanent View Controller Segue (outside of Navigation Controller)

Having some trouble permanently moving one from view controller to another. The normal segues seem to all have a 'go back' option.
I know I can imbed the VC in a navigation controller and create a custom segue which rewrites the hierarchy/changes root VC
class ReplaceSegue: UIStoryboardSegue {
override func perform() {
source.navigationController?.setViewControllers([self.destination], animated: false)
}
}
But I want to avoid a navigation controller as it will confuse things when I add a SWRevealViewController later.
Can/Should I change the storyboard VC (outside of AppDelegate that is)?
Thanks - apologies if this is a 'beginner' question
You can either change rootViewController of your main window:
self.window.rootViewController = vc
or you can just simply set vc's modalPresentationStyle to fullscreen (this doesn't have a "go back" option by itself, only you can dismiss it calling dismiss)
let vc = UIViewController()
vc.modalPresentationStyle = .fullScreen
or from storyboard change it's presentation style to fullscreen.

How to maintain the navigation with a segue "present modally"?

I have : navigation controller -> tableViewController -> tab bar Controller -> ViewController1 / ViewController2 / ViewController3
I click on a cell on the TableViewController and I open the TabBar. All is OK
But, I wanted to have more details from the datas in the TableViewController so I decided to make a popup with the content of the cell. I found this tutorial https://www.youtube.com/watch?v=S5i8n_bqblE => GREAT ! It's about the use of segue "present modally" with a viewcontroller containing the popup. I made a link from the popup to the tabBarController and I lose the Navigation Bar
I tried to play with navigationBar but nothing is working. I changed the type of segue but I don't obtain what I want.
I think the problem come from the type of segue. It's OK if I use it like a go/back in viewController. Do you have any solution about using this sort of popup or do I have to use another way ?
Thanks
Ok, let's take a look.
Navigation Bar is a view which is provided by Navigation Controller. Sometimes we are confused with navigation bars and navigation items. Navigation bar is the only one and it belongs to navigation controller, navigation item belongs to individual view controller from navigation stack. So, first step is simple: if you want navigation bar, wrap your modally presented controller into navigation stack.
Yes, you will face other problem, the blurred view of previous controller will become a black area. Why? there is special object called Presentation Controller (UIPresentationController) which is responsible for how controller will be presented. And it hides view of previous controller by default (in sake of performance, I think).
Ok, let's move. We can create custom presentation controller and tell it not to hide view of previous controller. Like this:
class CustomPresentationController: UIPresentationController {
override var shouldRemovePresentersView: Bool {
return false
}
}
Next step. In controller we want present modally we have to specify to things: we want to use custom presentation controller and we also want to adjust delegate object for transitioning (where we can specify custom presentation controller). The trick is that you have to do it inside initialiser, because viewDidLoad is too late: controller had been already initialised:
class PopupViewController: UIViewController {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
modalPresentationStyle = .custom
transitioningDelegate = self
}
}
Final step. When PopupViewController became delegate for its own transitioning, it means this controller is responsible for all of them. In our particular case popup controller provides custom version of presentation controller. Like this:
extension PopupViewController: UIViewControllerTransitioningDelegate {
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
return CustomPresentationController(presentedViewController: presented, presenting: presenting)
}
}
That's all. Now you should see view of previous controller.

Performing segue with UINavigationController (without IBAction)

It's easier to show you a drawing and then explain.
Dashboard Storyboard
I have 2 separate UIViewControllers (i've included just one in the drawing, the other is irrelevant) embedded in container view called ContainerViewController.
Post Storyboard
NewPostViewController shows a UIButton that presents TextPostViewController. As you can see, all of them are embedded in UINavigationControllers. Now, once the completion block of the new post is being called, I have to present the ContainerViewController and it needs to handle it's own logic. The problem is that it's embedded in UINavigationController and once I present it, the UITaBbar is hidden.
I tried to do this:
self.performSegue(withIdentifier: "TextPostToNavContainerVC", sender: nil)
The transition is successful but I'm losing the UITabBar, even though in the DashboardViewController and the ContainerViewController I called:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
tabBarController?.tabBar.isHidden = false
}
What am I doing wrong or is there are better way to do that?
You should instantiate the tab bar controller. not the view controller.
Imagine you're putting a initial view controller ahead of your tab bar controller. Making your tab bar not being pushed
If I undestand it correctly.
You are doing this
Segue connect to a view controller
But you should actually do this Segue connected to a tab bar controller
You can try to add it as a child to control it's frame like this
let textPost = self.storyboard?.instantiateViewController(withIdentifier: "containerID") as! TextPostToNavContainerVC
textPost.view.frame = CGRect(x:20,y:0,width:self.view.frame.width,height:self.view.frame.height-50)
self.view.addSubview(nvc.view)
self.addChildViewController(textPost)
textPost.didMove(toParentViewController: self)

navigationController is nil in swift

I have two storyboard (Main and SB2)
I have one view controller in storyboard in Main and one in SB2
I perform
let SB2 = UIStoryboard(name: "SB2", bundle:nil)
let vc : UIViewController = self.SB2.instantiateViewControllerWithIdentifier("VC2")
self.showViewController(vc, sender: self)
After the second viewcontroller loads and this command is run, it prints nil:
print(self.navigationController) // prints nil
In SB2 (second storyboard) I clicked on the viewcontroller (VC2) and then clicked on Editor > Embed In > Navigation Controller. This placed a navigation controller with the storyboard and the root view controller is VC2. I triple checked this. The first sign of it being connected was the gray navigation bar on top. The second being that there is segue connecting the navigation controller to VC2 and the last place I could have checked is in the navigation controller utilities.
I am thinking that maybe I shouldn't transition from VC1 to VC2 directly but rather VC1 to NavigationController however I don't know how to do this or if its even possible.
I don't know when sb2 prints nil when in face a navigation controller is connected to it. Any help is appreciated.
You need to push the view controller (VC2) on to the navigation controller.
let SB2 = UIStoryboard(name: "SB2", bundle:nil)v
let nvc = SB2.instantiateViewControllerWithIdentifier("NVC") as! UINavigationController
let vc : UIViewController = self.SB2.instantiateViewControllerWithIdentifier("VC2")
nvc.pushViewController(vc, animated: true)
Then in your view controller try calling
self.navigationController
In your storyboard,
select the initial ViewController. With this view controller selected, choose the menu item
Editor -> Embed In -> Navigation Controller