Using Multiple Detail Views with Split View Controller - objective-c

As you know, a UISplitViewController has one root controller and one detail view controller only, but I want to use another detail view controller.
When I select the list items from the root controller (popover controller), the selection should fire different detail views -- i.e., row1 fires detail view1, row2 fires detail view2 and a button item fires detail view3, etc.
How can I achieve this?

That project from Apple is from 2012 and doesn't use storyboards. If you are looking for a non-storyboarded solution, it will work fine but in Xcode 6 you should be taking advantage of the new Show Detail segue in storyboards.
Here's a quick example project that shows how to use multiple detail view controllers on the same split view by using the Show Detail segue from the Master View Controller.

There's a project from Apple that covers exactly what you need. MultipleDetailViews
This sample shows how you can use UISplitViewController to manage
multiple detail views.
The application uses a split view controller with a table view
controller as the root view controller. When you make a selection in
the table view, a new view controller is created and set as the split
view controller's second view controller.
The root view controller defines a protocol
(SubstitutableDetailViewController) that detail view controllers must
adopt. The protocol specifies methods to hide and show the bar button
item controlling the popover.

In Swift
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let imageGalleryVC = storyBoard.instantiateViewController(withIdentifier: "ImageGallerySID") as! ImageGalleryViewController
splitViewController?.showDetailViewController(imageGalleryVC, sender: nil)
}

I know this is a late post as this was asked 6 years ago and active last year.
But there is a way to have multiple detail views for a split view controller.
By embedding each detail controller into its own navigation controller and linking from the master view to each using the 'show detail' segue, you are able to achieve this result of switching between views by using an identifier associated and then from the master view function 'didSelectRowAt' selecting a row is where you can select which detail view you wish to see.
if indexPath.row == 0 {
performSegue(withIdentifier: "secondView", sender: self)
}
if indexPath.row == 1 {
performSegue(withIdentifier: "thirdView", sender: self)
}

Related

How to present view controller behind another view controller?

I am trying to present two view controllers. I'm trying to avoid presenting one after the other as this doesn't give a good user experience.
I'm using storyboards / segues to present the view controllers, each embedded in navigation controllers.
The behaviour should be:
View Controller 1 presents view controller 2 - but when view controller 2 dismisses I'd like view controller 3 to be the one showing to the user. And ideally an ability to also dismiss to view controller 1.
I understand I can accomplish this with child views. But I'd ideally like to learn how it can be done by manipulating the navigation stack.
I don't think you can do what you want with segue, but certainly you can do it with a little code...
This will (on a button tap, for example) perform a standard slide-in navigation controller animation directly from the current ViewController (call it vc1) to ViewController2, but "insert" ViewController3 into the stack. Tapping the Back button will take you from vc2 to vc3 to vc1.
#IBAction func didTap(_ sender: Any) {
guard let vc3 = storyboard?.instantiateViewController(withIdentifier: "vc3"),
let vc2 = storyboard?.instantiateViewController(withIdentifier: "vc2")
else { return }
let vcArray = [self, vc3, vc2]
self.navigationController?.setViewControllers(vcArray, animated: true)
}
If you want to go from vc2 back to vc1 and "skip over" vc3, in vc2 add (on a button tap, for example):
#IBAction func backToStartTap(_ sender: Any) {
self.navigationController?.popToRootViewController(animated: true)
}
As best to my understanding about your question, try out below method:
Present VC 3 from VC 1 and from VC 3 present VC 2 immediately(This can be done by putting the viewController present code in the ViewDidLoad() of VC 3).
So when you dismiss VC 2, VC 3 will be shown and on dismissing VC 3 , you will be redirected to VC 1.
VC means ViewController.
Presenting viewController in the ViewDidLoad() is really a bad idea.
You can present VC3 and add VC1.view and VC2.view as a subview of VC3's view and later you can remove VC1.view and VC2.view as you want and behaviour will be same as you are expecting.
You need to set your the viewcontroller you are going to present .modalPresentationStyle as .currentContext, and you need to set your current viewcontroller .definesPresentationContext as false

UITabBarController not showing all the tabs

I've been having a weird issue with the UITabBarController. Here it is:
I created a new Single View application
I dragged and dropped Tab Bar Controller on to the storyboard which has two initial view controllers.
I created two classes for those two view controllers.
I dragged another view controller on to the storyboard and connected the UITabBar to this new view controller. So now the tab controller shows three tabs.
So the issue is sometimes the tabbar doesnt show the third tab at all. And sometimes it shows. I've no freakin idea why this is happening. Can anyone please me with this.
Anand.
I found that I had to set the title manually after creation for the tab to show up in the TabBarController. I still have no idea why...
let salesController = SalesController(nibName: nil, bundle: nil)
let orderReviewController = OrderReviewController(nibName: nil, bundle: nil)
let accountController = AccountController()
// need to set the title here instead of viewDidLoad() otherwise tab doesn't show up...wtf?
accountController.title = "Account"
viewControllers = [salesController, orderReviewController, accountController]
When you are creating Tabbar app using Single View application, create tabbar like this:
Select single view goto Menu Editor-->Embed In --> Select Tab Bar Controller.
Then drag drop your other two viewController.
Create a realetionShip Segue with viewController clean project it should be working.

Segue Unwind back to the last specific View controller

Is there a way to have one button unwind back to a specific view controller? For example suppose I have ViewController A and B. Both modally segue to ViewController C. Now I understand how to segue unwind back to one of the previous view controllers (As was explained here) but how do I go back to the specific view controller that presented VC C?
So to sum it up, what I'm trying to figure out is...
If A segued to C then I want to unwind back to A when the button is selected. If B segued to C then I want to unwind back to B when the button is selected.
You should use the standard way to return from a modal segue. Put this in your 'back' button...
[[self presentingViewController] dismissViewControllerAnimated:YES];
This doesn't use the storyboard or a segue for the return, just code.
You could use the presentingViewController 'title' property to steer the unwind process to the desired originating ViewController. This solution would also allow you to pass data from your ViewController C to ViewControllers A and B.
1) Select the View Controller button (the yellow one) at the top of the storyboard canvas of ViewController A.
2) In the Attributes Inspector (View Controller section) give ViewController A a title.
3) Include the following code in ViewController A:
#IBAction func returned(segue: UIStoryboardSegue) {
// Don't need any code here
}
4) Repeat steps 1, 2 and 3 for ViewController B.
5) Override the prepareForSegue function in ViewController C as follows:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if self.presentingViewController!.title! == "ViewControllerATitle" {
let destination = segue.destinationViewController as! ViewControllerA
destination.someFunction(someArgument)
}
else if self.presentingViewController!.title! == "ViewControllerBTitle" {
let destination = segue.destinationViewController as! ViewControllerB
destination.someFunction(someArgument)
}
}

UITableView on DetailView of SplitView doesn't load it's data

Using Xcode 4.3.1, ipad app for iOS 5.1, no core-data
On my storyboard I have a master-detail project. The master obviously has a TableView, and that works fine: by selecting an item in the master tableview my detail data is set in the detail view controller by the template code call setDetailItem (which I call from 'didSelectRowAtIndexPath'). That works fine.
My DetailView/Scene contains (another) UITableView (amongst other, also some TextFields etc.)
This UITAbleView's datasource and delegate are connected to the detail view controller.
In the detail viewcontroller's interface file I adde the protocols UITableViewDataSource and UITableViewDelegate (next to the pre-configured UISplitViewControllerDelegate).
I implemented the methods numberOfSectionsInTableView, numberOfRowsInSection, cellForRowAtIndexPath, didSelectRowAtIndexPath methods in the detail view controller.
However, these are only called when the master tableview's list is build up, not when I select an item in the master list/tableview. When I select an item in the master list/tableview the detail data get's set in the detail viewcontroller, but for instance the 'cellForRowAtIndexPath' in the detail controller is never called, and the detail TableView is not updated/initialised. (The textfield in the detail view however is loaded with the correct data).
I guess I am missing something. Do I have to give the tableview a kick at the point I prepared it's data? And if so, how...? The tableview itself is not connected to an outlet or action, should it?
Thanks!
You need to implement a custom delegate (one-to-one communication) from RootView to Detailview.
Like the following,
Implement the Delegate in RootView,
#protocol RootViewControllerDelegate <NSObject>
-(void)didchangeSelectionInRootViewList:(id)toItem;
#end
And call the delegate when needed as (in your case on table view didSelectRowAtIndexPath),
//a delegete need in caes of splitview to refresh the detailview.
-(void)callDelegate:(id)sender {
if(self.delegate && [self.delegate respondsToSelector:#selector(didchangeSelectionInRootViewList:)]) {
[self.delegate didchangeSelectionInRootViewList:sender];
}
}
And don't forgot to set the delegate in Rootview as detailview while creating splitview controller.
And also catch the delegate in Detailview and reload the TableView with sufficient data to load.
thanks,
Naveen Shan

Split-View Based Application - Navigation in RootViewController

Solved
Hey all,
I'm currently working on a Split-View Based Application for iPad. I want the Root View Controller to navigate to another TableView, and from there, the users can select the appropriate row and display the information in the DetailViewController. I managed to code the navigation part in (The Root View Controller navigates to another table instead of displaying information instantly to the Detail View Controller), but I can't seem to display information based on the user's TableView selection.
The Hierarchy of Selection is as follows:
RootViewController -->Select Row in Root View Controller --->Navigate to TableView-->Select Row from TableView-->Display in Detail View Controller
Any ideas?
Thanks.
Here was my solution, partly.
In didSelectRowAtIndexPath (delegate is my app delegate singleton):
[delegate setDetailItem:newFile];
setDetailItem:
- (void)setDetailItem:(id)newDetailItem
{
if (detailItem != newDetailItem)
{
[detailItem release];
detailItem = [newDetailItem retain];
}
detailViewController.detailItem = self.detailItem;
[self.detailViewController configureView];
}
the detailViewController has an (id) variable detailItem which i set from the row i selected. then i configure my detailview as needed based on this item. So there is a start for you.