Swift multiple subviews and getting back to original TableView - ios

I have created my own TabView the first tab is always the Home tab which contains a TableView . The other 3 Tabs Search, Menu and Inbox are subviews . I can go from
Home to Search then Back to Home and it works
Home to Menu then Back to Home and it works too
Home to Menu then to Search and back to Home brings me back to the Menu subview . I essentially want to eliminate all subviews when clicking the Home Tab . Also each TabView is in it's own controller .
This is my code
From Home Controller to Menu Controller
#IBAction func MenuTabAction(_ sender: UIButton) {
let Popup = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "MenuC") as! MenuC
self.addChildViewController(Popup)
Popup.view.frame = self.view.frame
Popup.view.tag = 100
self.view.addSubview(Popup.view)
Popup.didMove(toParentViewController: self)
}
From Menu Controller to Home Controller & Search Controller
#IBAction func HomeTabAction(_ sender: UIButton) {
if let viewWithTag = self.view.viewWithTag(100) {
print("Tag 100")
viewWithTag.removeFromSuperview()
}
}
#IBAction func SearchTabAction(_ sender: UIButton) {
let Popup = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "LocalSearchC") as! LocalSearchC
Popup.view.frame = self.view.frame
Popup.view.tag = 100
self.view.addSubview(Popup.view)
Popup.didMove(toParentViewController: self)
}
I am guessing that the remove superview only removes 1 superview at a time so if I go from Subview1 to subview2 then click on the HomeTab it brings me to subview1 instead of the original HomeTab . Is there a way to remove all superview/subviews when clicking the Home Tab ?

Each Tab got it's own view controller. Ideally, you should removeFromSuperview all controllers you're not showing.
At your code, you only removeFromSuperView at HomeTabAction.
Try to change it:
if let viewWithTag = self.view.viewWithTag(100) {
print("Tag 100")
viewWithTag.removeFromSuperview()
}
to
for v in self.view.subviews {
if v.tag == 100 {
v.removeFromSuperview()
}
}
But please, keep in mind that each time a user press any tabs without returning to home (i.e: tapping many times between Menu and Search), it's look like you are just instantiating many controllers, without removing them.
You should remove other Views every time a new one is instantiated. Would be wise to give a unique tag to each view controller and remove the hidden others after every change, not only when returning to Home. Or at least, check if the view controller with a given type already is instantiated before create a new one.

Actually, you don't need to manually instantiate the viewcontrollers (LocalSearch, Menu). TabViewcontrollers can link a vc with each tab item via a segue. In fact, when you add your tabvc to the project, it will come with 2 viewcontrollers, each connected to an item in the tabview, and that's it, you just need to replace them or adapt them, no need to "load" them.
The only scenario where you'd need to do this, is if your buttons were "dynamic", as in, the content to be loaded changes depending on some other circumstances. As long as clicking "Search" goes to LocalSearchViewController, just link it with a segue on the storyboard.

Related

Put tab bar to all the viewcontrollers

I've created a Tabbar with UIView what I want is to put this tab bar view on every storyboard this tabbar transfers to.
I tried connecting all the tab bar elements to a button code below and open the storyboard, but the tab bar doesn't show up. any solutions ?
#IBAction func tabBarClick(_ sender: UIButton) {
let storyboard = UIStoryboard(name: "Saved", bundle: nil)
print(sender.tag)
if sender.tag == 3 {
guard let savedView = storyboard.instantiateViewController(withIdentifier: "SavedViewController") as? SavedViewController else {
return
}
contentView.addSubview(savedView.view)
savedView.didMove(toParent: self)
}
}
If you created your custom tabbar, the only way to achieve the expected behavior is to create a custom container view controller and put child controllers in it. You can read more about create container controllers here

How to Connect More than One View Controller to Navigation Controller

I have the following storyboards:
"Home" is the default view controller. When you press the button in the top left with three lines, the menu view controller slides out (it's like a side menu). Within the menu there are four table cells that represent menu items, as you can see. When a cell is pressed, I have a corresponding function that is called. I want the view controller on the far right to be presented when a cell is pressed.
Here's the issue: I want the far right view controller to inherit the properties of the Home view controller, such that the navigation title and button are still there. How can I achieve this?
Here's the solution:
Make sure that the navigation and right view controller are segued (Ctrl + Drag in Interface Builder)
Call the code stated in #bebzerk answer:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let transition = storyboard.instantiateViewController(withIdentifier: "RightViewController") as! RightViewController
navigationController?.pushViewController(transition, animated: true)
Now go back to Interface builder, and add a UINavigationItem and a UIBarButtonItem to the view controller. Set the image of the button to the three lines and set the title of the navigation item to the name you want displayed on the top.
In the ViewController Swift file for the right view controller, Ctrl + Drag the bar button item and create an IBAction function. This will be called when the menu button (on the far right view controller is pressed). For me, this class extends from HomeViewController, so in the function, just called the super method. It should look like this:
#IBAction override func menuTapped(_ sender: UIBarButtonItem) {
super.menuTapped(UIBarButtonItem())
}
This should achieve the desired function.
Did you try this way ?
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let transition = storyboard.instantiateViewController(withIdentifier: "RightViewController") as! RightViewController
navigationController?.pushViewController(transition, animated: true)
It should open your far right view controller and makes it inherit your home controller, like with a back button
Test it and tell me if it's good to you.

Back button in Navigation bar not displayed

I have a view controller connected to a popover controller, which directs to a new view controller. I want to add a back button on the navigation item to the last view controller so that when I click back it will return to the first view controller
I tried creating segue and click action in the popover controller and add back button in the segue function/click action function
neither of them works
This is what I do in the Popover. I already present the popover with UIPopoverPresentationControllerDelegate and this is what PopoverVC looks like. In this way, I add IBAction to enable the click action of the label in popover. I write the backbutton in the IBAction function and create the navigationcontroller with rootview, and the back button doesn't appear.
class PopoverViewController: UIViewController {
//TODO: add BACK button
#IBAction func createNewChat(_ sender: Any) {
let storyboard = UIStoryboard(name: "Main", bundle:nil)
let contactVC = storyboard.instantiateViewController(withIdentifier: "contacts") as? NewContactsViewController
let nc2 = UINavigationController()
let back = UIBarButtonItem()
back.title = "Back"
nc2.navigationItem.backBarButtonItem = back
nc2.pushViewController(contactVC!, animated: true)
self.present(nc2, animated: true, completion: nil)
}
}
I also tried another way, I create a segue in storyboard and connect the popover to the navigation controller, the backbutton still doesn't appear.The segue is hooked up to the navigation controller in the storyboard.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let seg = segue.destination as! ContactsTableViewController
let back = UIBarButtonItem()
back.title = "Back"
navigationItem.backBarButtonItem = back
}
My question is: how to make the back button appear? After it appears, how to make it work? I don't want the back button points to the popover, I want the back button will make users return to the VC that creates the popoverVC.
The back button in a navigation bar doesn't belong to THIS view controller; it is the back button item of the previous view controller already on the navigation stack. But you have no previous view controller. So just use, like, a left bar button item that says Back, or something.
Thus, give the bar button item (back) an action and target and change
nc2.navigationItem.backBarButtonItem = back
to
nc2.navigationItem.leftBarButtonItem = back

Toggle ViewController Views

I am learning iOS with few sample projects. I have two view controllers in that first VC has few buttons and a mapview and the second VC has tableview showing a set of results. I have embed the both viewcontrollers in navigationViewController.By clicking a button from First VC i am able to show the tableview (using show segue) and able to go back to first VC through navigation. Now my query is I want to display the tableview (second VC) in place of one view object (map view) defined in firstVC rather than padding the tableview entirely in full screen. My problem is when showing another Viewcontroller i still want to see the few viewobjects from firstVC so I am trying to display the secondVC on top of mapview when i click on a button which triggers the segue.I have to use the single interface, so I need to load the tablview results from SecondVC into firstVC by replacing mapView's view with tableview.Please let me know your ideas if it is possible and any other ideas to achieve the same are most welcomed.
Sreekanth Gundlapalli,
All you need to do is to add the TableView controller's view as subview to your view Controller. In order to simplify the process I personally prefer using the ContainerView,
Step 1 : Add a ContainerView to your View Controller and add the auto layout constraints to it, because your tableView will be loaded inside this container view you donate have to apply any auto layout constraint to your tableView to keep it in place :)
ex :
Step 2 : Drag an IBOutlet to the container view.lets call it as containerView :)
Step 3 : Now its up to you to have two view controller 1 for loading map and 1 for loading tableView, or you will have map view as your view controller subview and you will either hide it or remove it and add container view but I personally prefer having code clean n neat so I prefer having two different VCs
so lets create 2 VCs lets call them as viewController1 & viewController2 Savy ??
Step 4 :
lets write a method which actually loads VC and adds its view as subview to your ViewController
func changeEmbededVC(for status : Int) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if status == 0 {
mehereButton.tag = 1
let vc = storyboard.instantiateViewController(withIdentifier: "viewController1")
vc.willMove(toParentViewController: self)
containerView.addSubview(vc.view)
self.addChildViewController(vc)
vc.didMove(toParentViewController: self)
}
else {
mehereButton.tag = 0
let vc = storyboard.instantiateViewController(withIdentifier: "viewController2")
vc.willMove(toParentViewController: self)
containerView.addSubview(vc.view)
self.addChildViewController(vc)
vc.didMove(toParentViewController: self)
}
}
I believe code is pretty self explanatory :D now what is mehereButton.tag = 1 ?? Simple you want to toggle view on button press don't you :D hence I have created a IBOutlet for mehereButton and changing its tag :)
now finally in IBAction of mehereButton
#IBAction func buttonTapped(_ sender: UIButton) {
self.changeEmbededVC(for: self.mehereButton.tag)
}
but we need to load one of the view by default isn't it :D
so change your viewDidAppear to
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.changeEmbededVC(for: 0)
}
Hope I answered your question In detail :P I know you can't neither up vote or accept answer as you don't have enough reputation :) but hope it will help somebody in future as well :)

How to navigate from popoverpresentation view controller to another view controller

I have a screen with a navigation controller and it has a button on the nav bar which displays a table (from another view controller) to select things from using pop over presentation, now on clicking any of those items i want to open another view controller a different screen.
BUT if i use navigationController?.pushViewController(tab, animated: true)
the new view controller is displayed within that small pop view itself
and if i use
navigationController?.presentViewController(tab, animated: true)
the navigation bar isn't there on that screen and i cannot go back to the previous screen. How to do it in such a way that i can go back to the screen which first displayed the pop Up list.
If you are using a Storyboard, it's really easy to do. If you're not, then you should. It's very good to use a Storyboard.
Let's call your view controllers these names:
The view controller that can show the popover is called SourceVC
The popover controller is called PopoverVC
The view controller to show when the user selects something from the table view is called NewVC
Add a show segue connecting your SourceVC to your NewVC. Give the segue an identifier.
Add an unwind segue that unwinds from PopoverVC to SourceVC. First, add these methods in your SourceVC:
func unwind(segue: UIStoryboardSegue) {
if let vc = segue.sourceViewController as? PopoverVC {
// get the thing that the user selected and store it somewhere
// perform a segue that shows NewVC
}
}
override func prepareForSegue(segue: UIStoryboardSegue) {
if let vc = segue.destinationViewController as? NewVC {
// pass the thing that the user selected to the NewVC
}
}
Then, select the PopoverVC and control drag it to the "Exit" thingy in SourceVC. And select "unwind:". Give this unwind segue an identifier as well.
When the user selects a row in the table view, just perform the unwind segue and store the thing that the user selected in a class-level variable so that you can pass it to SourceVC.

Resources