Multiple DetailViewControllers using a UISplitViewController - ios

Currently, I have a SplitViewController with a MasterViewController and a DetailViewController. I was wondering whether there's a way to have more DetailViewControllers. Right now I have a list of items in the tableView to the left and if you click on them, they go to a fullscreen view. How can I keep I have it to show inside the panel to the right of the splitview when clicked on instead? So with reference to this image - how can I get my view to display like the colour yellow in the detail section? Right now when I click on my equivalent of "yellow" - the colour yellow is shown fullscreen, and not as the detail. http://2uagoo1zzsoo4bcz3347bs2y.wpengine.netdna-cdn.com/wp-content/uploads/2012/08/Image003.png
extra info:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row == 0 {
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc: UINavigationController = storyboard.instantiateViewControllerWithIdentifier("newViewController") as! UINavigationController
self.presentViewController (vc, animated: true, completion: nil)
} else if indexPath.row == 3 {
let storyboardTwo: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vcTwo: UINavigationController = storyboardTwo.instantiateViewControllerWithIdentifier("newViewController4") as! UINavigationController
self.presentViewController(vcTwo, animated: true, completion: nil)
}

I believe you need to use the show showDetailViewController method:
Presents the specified view controller as the secondary view controller of the split view interface.
func showDetailViewController(_ vc: UIViewController,
sender sender: AnyObject?)
So in your case it would be used more like this. In the didSelectRowAtIndexPath function:
{
let vc:UIViewController
if indexPath.row == 0 {
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
vc: UINavigationController = storyboard.instantiateViewControllerWithIdentifier("newViewController") as! UINavigationController
} else if indexPath.row == 3 {
let storyboardTwo: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
vc: UINavigationController = storyboardTwo.instantiateViewControllerWithIdentifier("newViewController4") as! UINavigationController
}else {
// handle this case
vc = ...
}
// Grab the Split View Controller
let splitVC = // get Split View Controller
splitVC.showDetailViewController(vc,sender:nil)
}

Related

Pass data between more than two view controllers using delegation

First of all, let me say that I have been using the delegation pattern to pass data back and forward between view controllers for quite some time without any issues but now I have a need to pass data between four (4) view controllers, ViewController1, ViewController2, ViewController3 and CategoriesViewController.
In the code below I'm showing the communication between ViewController1 and the CategoriesViewController, the communication between ViewController2 and CategoriesViewController will be identical as well.
My issue or what I don't quite like is the fact that I don't need to pass any data between ViewController3 and the CategoriesViewController so, my debate is how can I handle the fact that CategoriesViewController is expecting variable categoryTracker which I will not be passing when connecting ViewController3 with the CategoriesViewController.
Is there a way to make the variable categoryTracker in CategoriesViewController optional, here I'm talking in a sense that I wouldn't have to pass it when connecting from ViewController3 and NOT a Swift optional?
How would you guys do such communication in a way that CategoriesViewController becomes more modular/reusable?
ViewController1 and ViewController2
class ViewController1: UIViewController, CategoryDelegate{
#IBAction func showCategories(_ sender: Any) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "categoriesViewControllerID") as? CategoriesViewController
vc?.delegate = self
vc?.categoryTracker = self.categorySelection
self.present(vc!, animated: true, completion: nil)
}
}
CategoriesViewController
protocol CategoryDelegate {
func selectedCategory(category: Category)
}
class CategoriesViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var delegate: CategoryDelegate?
var categoryTracker:Category?
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
delegate?.selectedCategory(category: categoryTracker!)
}
}
Just for reference, here is how ViewController3 would look like.
class ViewController3: UIViewController{
#IBAction func showCategories(_ sender: Any) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "categoriesViewControllerID") as? CategoriesViewController
self.present(vc!, animated: true, completion: nil)
}
}
Thanks

self.navigationController?.pushViewController not Working Swift

I have CollectionViewController, when I am trying to click on cell and navigate to respective ViewControllers its not working.how can I solve this issue.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell:AddOptionCollectionViewCell = collectionView.cellForItem(at: indexPath) as! AddOptionCollectionViewCell
if (cell.name.text == "CONTRAST"){
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let newViewController = storyBoard.instantiateViewController(withIdentifier: "ContrastViewController") as! ContrastViewController
self.navigationController?.pushViewController(newViewController, animated: true)
}
I think this problem is due to nil value of navigation stack for your CollectionViewController class.
So, first of all go to storyboard and select CollectionViewController class and embed NavigationController into it. After this try and run it will work.
All the best.
In my case, I mistakenly added the MainViewController to the window.rootViewController instead of adding it to the UINavigationController and then using the navigation as rootViewController.
at SceneDelegate.swift, it should be:
let navigationController = UINavigationController()
navigationController.pushViewController(MainRouter.createModule(using: navigationController), animated: false)
window.rootViewController = navigationController
window.makeKeyAndVisible()

How to dismiss previous view controller and move to next view controller in Swift iOS

in my application i am using a UITableView as a navigation menu for my app, it has 5 cells, 'Home', 'Order Online', 'Gallery', 'Contact', 'About'.
how it works is, when the user clicks the menu button the UITableView Menu pops down and then when a cell is clicked the correct UIViewController is loaded.
Now, the problem is, the previous view controller that was presented (before i move to a new controller via the tableView menu) is not dismissed. so in the app i can present the 'order online' view controller multiple times which obviously causes a memory problem,
BUT i do not want the view controller to be dismissed when it presents the tableView as i am using a custom transition where the tableview slides down half way down the screen so a snapshot of the previous controller should still be present, only when a cell is clicked in the tableView and a new view controller is presented, should the view controller loaded before the tableView be dismissed.
here is a screenshot of storyboard :
here are some screenshots:
here is all the 'relevant' code from my TableViewController that is used as the navigation menu:
class MenuTableViewController: UITableViewController {
var menuItems = ["Home", "Order Online", "Gallery", "Contact Us", "About"]
var currentItem = "Home"
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! MenuTableViewCell
// Configure the cell...
cell.titleLabel.text = menuItems[indexPath.row]
cell.titleLabel.textColor = (menuItems[indexPath.row] == currentItem) ? UIColor.white : UIColor.gray
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if (indexPath.row == 0) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "homeView")
self.present(controller, animated: true, completion: nil)
}
if (indexPath.row == 1) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "orderView")
self.present(controller, animated: true, completion: nil)
}
if (indexPath.row == 2) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "galleryView")
self.present(controller, animated: true, completion: nil)
}
if (indexPath.row == 3) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "contactView")
self.present(controller, animated: true, completion: nil)
}
if (indexPath.row == 4) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "aboutView")
self.present(controller, animated: true, completion: nil)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let menuTableViewController = segue.source as! MenuTableViewController
if menuTableViewController.tableView.indexPathForSelectedRow != nil {
}
}
}
i have tried using
self.dismiss(animated: true, completion: nil)
in a number of ways but it just doesn't make the app work the way i want it to, any help will be appreciated.
In you didSelectRowAt method, you are instantiating a new instance of the view controller every time you are to present the new controllers.
You could simply instantiate them beforehand (perhaps within viewDidLoad) within your menuTableViewController, then reuse the same instances of the controllers. Doing this will also allow you to be able to dismiss them from the menuTableViewController class as it is holding references to each of the new Controllers.
If you are creating one, i suggest to use ONE custom navigation controller for the down menu + button, and it will control the content menu and vc, if you want to change it's root vc, just simply set vc of that custom navigation controller with self.setViewControllers([vc], animated: true), other vc will automatically dismiss itself

pushViewController don't work when my tableView is in an TabBar

I have a TableViewController in a TabBar.
When I select one cell of my tableView, I want start a new controller with pushViewController(MyNewController).
This is my code :
In my TableView :
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let myController = (storyboard.instantiateViewControllerWithIdentifier("MyViewController") as? MyViewController)!
myController.parameter = self.tableau[indexPath.row]
UINavigationController().pushViewController(myController, animated: true)
}
In my TabBar :
func viewDidLoad() {
super.viewDidLoad()
var controllerArray: [UIViewController] = []
let controller: UIViewController = ClubPreviewListViewController()
controller.title = "TEST"
controllerArray.append(controller)
self.view.addSubview(pageMenu!.view)
}
(I use CAPSPageMenu for customize my TabBar, but it's not the problem, I have the same problem without)
In my controller :
deinit {
print ("TEST")
}
When I select a cell, the log write "TEST" everytime I select but don't change the view.
I think it's my navigationController the problem, but I don't know how to fix it.
Before I implement the TabBar, I use my TableView alone, and the push did works.
Sorry for my english ! Thanks for your help.
EDIT:
I change my pushViewController :
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let myController = (storyboard.instantiateViewControllerWithIdentifier("MyViewController") as? MyViewController)!
myController.parameter = self.tableau[indexPath.row]
//UINavigationController().pushViewController(myController, animated: true)
self.navigationController?.pushViewController(myController, animated: true)
}
Same reaction.
My NavigationController isn't directly link with my TabBar. I need to create an other one ? I don't really understand how NavigationController works !
This is my configuration
EDIT2:
If I use the navigationController of my TabBar and not of my TableView, the view change !
self.saveTabBarNavigationController.pushViewController(myController, animated: true)
You are creating an instance of a navigation controller on the line
UINavigationController().pushViewController(myController, animated: true)
Once this method finishes executing, the navigation controller and its view controllers will be deallocated because nothing retains your navigation controller. Causing 'TEST' to be printed in your deinit() function.
You should be obtaining the navigation controller that owns your current tab bar controller and pushing onto the stack using that. Without knowing the structure of your application it is difficult to know where your navigation controller is (if it exists).
Check your storyboard, but essentially try:
self.navigationController.pushViewController(myController, animated: true)
Try this it will work only if you have a navigation embedded tabbar controller
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let myController = (storyboard.instantiateViewControllerWithIdentifier("MyViewController") as? MyViewController)!
myController.parameter = self.tableau[indexPath.row]
navigationController.pushViewController(myController, animated: true)
}

Swift: pass string value from VC2 to VC1 on dismissViewControllerAnimated

first time asking after learning many useful things here!
I have a VC1 with a button and label.
The button is coded to present VC2 programmatically (without segue in IB).
VC2 has a tableview with the cells containing string values.
When I click on the cell in VC2, I am trying to get the string value of the selected cell and pass it back to the label.text in VC1.
First ViewController code:
class VC1: UIViewController {
... ...
#IBOutlet weak var LabelText: UILabel!
var passedString = "Example"
override func viewWillAppear(animated: Bool) {
LabelText.text = "\(passedString)"
}
#IBAction func chooseLabelTextBtnPressed(sender: AnyObject) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("VC2") as! VC2
self.presentViewController(vc, animated: true, completion: nil)
}
SecondViewController code:
class VC2: UIViewController, UITableViewDelegate, UITableViewDataSource {
... ...
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// Get Cell Label
let indexPath = tableView.indexPathForSelectedRow;
let currentCell = tableView.cellForRowAtIndexPath(indexPath!) as! VC2_tableViewCell!;
let valueToPass = currentCell.IBOutletLbl.text
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewControllerWithIdentifier("VC1") as! VC1
viewController.passedString = valueToPass!
//self.presentViewController(viewController, animated: true , completion: nil)
self.dismissViewControllerAnimated(true, completion: nil)
}
I hoped func viewWillAppear() in VC1 would update the String value of the label when VC2 is dismissed, but it doesn't.
I cannot use presentViewController from VC2 to VC1, because it might open again the VC1 instead of going back, and then other variables in VC1 would be inaccessible.
Help me! Thanks!
You should pass a delegate from VC1 to VC2 and then just call a delegate method for the update.
Send a reference here to VC2.
#IBAction func chooseLabelTextBtnPressed(sender: AnyObject) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("VC2") as! VC2
vc.delegate = self
self.presentViewController(vc, animated: true, completion: nil)
}
And before calling self.dismissViewControllerAnimated(true, completion: nil) in VC2 just call delegate.someMethod(someValue)
Also make sure your delegate is a weak reference.
When you do this:
let viewController = storyboard.instantiateViewControllerWithIdentifier("VC1") as! VC1
It creates a new instance of VC1 and doesn't actually reference the VC1 that presented VC2.
Instead you should add delegation between VC1 & VC2 to pass data around.

Resources