Invoking a segue associated with the Detail View from the Main View - ios

I have a split view controller and the main view has a "Note" button on a navigation bar which should push a view(Note Gallery ViewController) that contains a list of saved notes onto Detail View. In the following screenshot, "Categories" is the Master View and "List of Events" is the Detail View. As you can see, there is a segue between the "List of Events" and "Note Gallery".
What I would like to do is pushing the "Note Gallery" as a Detail view when "Note" button on the Main View is tapped. So far, I have tried using delegate/protocal approach where protocol is defined inside the Master View and it is implemented inside the Detail View. If I call self.performSegue to push "Note Gallery" view, "Note Gallery" view does not show navigation bar (Even if I force it to show with setNavigationBarHidden with false value). If I call performSegue from the navigation controller (self.navigationController?.performSegue), I get identifier not found exception. I don't want to move Note button to the Detail view since I want to make Note button accessible from the Main View. How can I resolve this issu, and here's an excerpt of my code :
/* Master View */
// Define delegate for updating children views
protocol ChildViewDelegate: class {
func pushInNoteView()
}
class MasterViewController: UITableViewController, NSFetchedResultsControllerDelegate {
weak var delegate: ChildViewDelegate?
// Handles tapping on Note button
#IBAction func noteTapped(_ sender: UIBarButtonItem) {
// Push Note View onto any active detailed view
self.delegate?.pushInNoteView()
}
}
/* Detail View */
extension CategoryDetailTableViewController: ChildViewDelegate {
func pushInNoteView() {
// This approach does not show navigation bar
self.performSegue(withIdentifier: "showNoteView", sender: self)
// This approach gives identifier not found exception
self.navigationController?.performSegue(withIdentifier: "showNoteView", sender: self)
}
}

I assume the problem is that you did not give identifier to your segue in main.storyboard.
Here is how to do it.
In your main.storyboard select your segue as shown in image and assign it an identifier in identity inspector as shown in top right side of the image.
Now create navigation controller and make "root view controller" relationship with your Master View. Then use performSegue(withIdentifier: "segue", sender: nil) to move to next view controller.
Hope that I've solved your problem!

Here are the mistakes I have made :
The reason why I'm getting identifier not defined error is because the segue is not connected between the navigation controller and the "Note Gallery" view. It's connected between the "Note Gallery" view and the "Category Detail" view which in turn connected to the navigation controller. Therefore, the identifier is not defined for the navigation controller.
The reason why navigation bar is hidden is because I'm not pushing "Note Gallery" view onto the navigation controller. Instead, I was just calling prepare segue.
Solution :
It's fairly simple. I just push the "Note Gallery" view on the Navigation Controller just like this :
if let noteVC = storyboard?.instantiateViewController(withIdentifier: "NoteGalleryView") {
self.navigationController?.pushViewController(noteVC, animated: true)
}

Related

How to segue from tab bar view controller to another view which is a child of a navigation controller

I laid out my home screen (Summary screen) as shown on the screenshot below:
I added the "+" button on the UITabBarController subclass. This button will segue to a view controller and show it modally. To give you a bit of context on how I've structured my storyboards, please refer to the screenshot below:
This modal view controller has a form that the user needs to fill in, and once they're done, there's a 'Done' button which will 1) dismiss the modal, 2) take them back to the root view which is either the 'Summary' tab or the 'Details' tab then 3) take them to a list view showing the most recent data they've entered on a list (destination view – highlighted in red).
Now, doing the segue when the user taps the "+" button is simple enough. With the following code:"
menuButton.addTarget(self, action: #selector(menuButtonAction(sender:)), for: .touchUpInside)
then
func addNewExpense(action: UIAlertAction){
self.performSegue(withIdentifier: "segue_formModal", sender: self)
}
On the modal I've setup a protocol which will then send the form data back to the tab view controller.
extension XtabBarViewController: NewInfoDelegate{
func newInfoSubmitted(formData: FormData) {
performSegue(withIdentifier: "segue_ListingPage", sender: self)
}
}
But it seems that the perform segue is not working. It says the segue does not exist. "segue_ListingPage" is that segue that connects the Summary view and the destination view.
How can I segue from the tab bar view controller to the destination view? Any help is appreciated.
Thanks in advance!
You can just make the navigation view controller the entry point.
I figured it out on my own. For the benefit of those who run into the same issue here's my solution.
I simply added the code from the tab bar view controller the code:
let childVC = children[0].children[0]
childVC.performSegue(withIdentifier: "segue_TXListPage", sender: self)
So what I did here is call the performSegue from the view controller that segues to the destination controller.

Viewcontroller's navigation bar is added below navigation controller's navigation bar inside tab bar controller

I have a Tab Bar Controller that has a navigationcontroller with a view controller attached.
For some unknown reason the navigation bar of the view controller does not look like it always does. Instead the view controller's navigation bar is added below the navigation controller's.
When I look at the view controllers embedded in the first navigation controller before the Tab Bar Controller is shown, it works as expected.
This it what it should look like
And this
Now when I segue to the Tab Bar Controller which has a new navigation controller with a view controller embedded it looks like this:
I don't want an additional navigation bar below the one provided by the navigation controller.
I want the title and the item of the view controller merged with the navigation controller.
So the final result should display a row with the back button, the title and the bar button item(Search Image)
What am I missing?
I've also tried adding the navigation items programmatically but nothing seemed to work.
Project on github
My Code
//
// SideViewController.swift
// Sample
//
// Created by on 08.02.20.
// Copyright © 2020 . All rights reserved.
//
import UIKit
class SideViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
title = "Search"
}
#objc func action(){
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
There is two ways that I found you can resolve this either by presenting tab bar controller modally or hiding navigation bar of a tab bar controller when view loads.
First solution can be achieved like this:
Open Main.storyboard.
Select last segue in this storyboard(one that navigates to Side storyboard).
Make sure that you have Attribute Inspector selected. Now change Kind attribute to Present Modally and Presentation attribute to Full Screen.
And second solution can be achieved like this:
Create new file by selecting File > New > File > Cocoa Touch Class and press Next.
Change Subclass of: to UITabBarController and name your class to whatever make sense to you.
Then inside of viewDidLoad() paste this navigationController?.navigationBar.isHidden = true in order to hide current navigation bar.
Assign your class to TabViewController in the Side storyboard by selecting TabViewController and changing Class attribute to your class name in Identity Inspector. It should autocomplete when you entering your class name. Press Enter to make sure that you confirm the changes.
Remember to make just one of this two solutions. Which one would it be is up to your needs.

UIView container disappears after adding child view controller

I have a tab bar controller that has two tabs. One is a regular UIViewController and the other is a navigation controller. The navigation controller, I am able to push another view controller on it with a custom inputContainerView with no problems. But when I put a navigationViewController (name from mapbox) on the first tab as a child view, the custom inputContainerView no longer shows up. Even after I remove the child view controller from the first tab.
Adding child to tab 1
...
addChild(navigationViewController)
navigationViewController.view.frame = view.bounds
view.addSubview(navigationViewController.view)
navigationViewController.didMove(toParent: self)
}
func navigationViewControllerDidDismiss(_ navigationViewController: NavigationViewController, byCanceling canceled: Bool) {
navigationViewController.willMove(toParent: nil)
navigationViewController.view.removeFromSuperview()
navigationViewController.removeFromParent()
}
tab 2
override var inputAccessoryView: UIView? {
get { return inputContainerView }
}
override var canBecomeFirstResponder: Bool { return true }
The sequence I am trying to achieve is to add a child view controller to the first tab (navigationViewController which is named this from mapbox) click on the second tab and push a ui view controller on with the inputContainerView showing up. It shows up fine before I add the child view on the first tab but disappears after that
this is what the documentation says:
This method creates a parent-child relationship between the current view controller and the object in the childController parameter. This relationship is necessary when embedding the child view controller’s view into the current view controller’s content. If the new child view controller is already the child of a container view controller, it is removed from that container before being added.
Check the Highlighted part.

View controller view getting misplaced when navigating back to the home screen of UITabbarController

I have a tabbarcontroller in my application and have added view controllers with the help of storyboard and segues,
When i am in the second tabbar item I have a table view embedded with a navigation controller filled with usernames and on top I have a hamburger icon, I select a particular item from the table list present in the hamburger icon and navigate to the details view controller I have used segues and given below is the code for the same
self.performSegueWithIdentifier("MY_DETAIL_SEGUE_NAME", sender: nil)
MY_DETAIL_SEGUE_NAME is actually a custom push segue of the SWRevealViewControllerSeguePushController, the push is working fine and i am able to navigate to the details screen.
The Problem: Since I am in the second tabbar item on the hit of back button i need to show the inital view / home view controller of the second tabbar item which is the friend view list, so on the back button i have written the below code in the detail screen
#IBAction func moveBackToController(sender: AnyObject) {
self.performSegueWithIdentifier("showFriendListPage", sender: nil)
}
showFriendListPage: This is a custom segue to the firendlist page using the SWRevealViewControllerSeguePushController and is pointed to the tabbarcontroller
To highlight the second tabbar item i have used the below code written in the detail screen
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
let objParentTabbar = segue.destinationViewController as! ParentTabbarController
if segue.identifier == "showFriendListPage" {
objParentTabbar.selectedIndex = 1
}
}
What happening here is when i navigate back to the home screen of the second tabbar item my view is distorted i.e. the UI elements are not placed in a correct order which they were when i first went to the second tabbar
Note: All my view controllers are embedded inside the navigation controller so the structure is
TabbarController----->NavigationController------>ViewController
Please suggest where I am going wrong and what needs to be done to resolve this, my only struggle is the view getting distorted and i dont really know why is this happening.
Call the view your controller via code in your application should do the trick
objParentTabbar.selectedViewController?.viewWillAppear(true)

Showing and Popping Multiple View Controllers

So here's my problem.
First ViewController has some fields regarding name, date, no. of people of an Event (the user creates and event). It also has a button that will transition the user to a new viewController with a mapView where user will create a Pin. After user creates a Pin, user can press the pin (or do some other action that confirms that the Pin user put on the map is correct) and user will be transitioned to a new tableViewController with multiple locations near the Pin he selected (using Foursquare API).
Then the user must be transitioned to the first ViewController. The Location user tapped must be sent to the first ViewController.
This is my first time working with multiple ViewControllers and I need your help.
How would I do this (don't miss on any details please :D) ?
Use an unwind segue to pass data backwards through view controllers embedded in a navigation controller.
Here's a brief example.
In your first view controller you can have something like:
var text: String?
#IBAction func unwindSegue(segue: UIStoryboardSegue) {
if let viewController = segue.sourceViewController as? ViewController2 {
text = viewController.textField.text
}
print(text!)
}
Add the unwind segue in the second view controller on the storyboard by ctrl-dragging from the view controller (yellow circle with a square in, to the exit icon (either at the top of the view controller or in the document outline) and click on the unwind segue that you created to create a manual segue. Then in the document outline set the unwind segue's identifier so that you can refer to it (I've called it simply "Unwind" for this example).
In the second view controller (the one you want to pass back from) add this:
#IBOutlet var textField: UITextField!
#IBAction func backButton(sender: AnyObject) {
self.performSegueWithIdentifier("Unwind", sender: nil)
}
This simple example will let you pass back the text from the textField in your second view controller.
n.b. You can unwind more than one view at a time.

Resources