In a split view controller app, how can I push multiple detail view controllers upon selecting a table row in the master view controller?
Just to be clear, I have splitviewcontroller with two different class:
1) MasterViewController - left handside View.
2) DetailViewController - right handside view
I need to add multiple ViewController above the DetailViewController using PushViewController (as a Stack), when I select a row in the master view controller. How do I wire up the view controllers? From the split view controller? or from the detail view navigation controller?
Assuming you want to replace the second view controller with another one, you can should be able to access the UISplitViewController via the parentViewController property of your master view controller and set a new viewControllers array. (See documentation at https://developer.apple.com/library/ios/documentation/uikit/reference/UISplitViewController_class/Reference/Reference.html)
- (void)tableView:(UITableView *)tv didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// ...
self.parentViewController.viewControllers = #[self, newViewController];
}
Assuming you are in your master view controller containing the table and it has a reference to the currently presented view controller which is a UINavigationController you can probably push the desired new view controller on the stack, no matter how often:
- (void)tableView:(UITableView *)tv didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// ...
[self.detailViewController pushViewController:vc1 animated:YES];
[self.detailViewController pushViewController:vc2 animated:YES];
[self.detailViewController pushViewController:vc3 animated:YES];
}
This will add three view controllers to the view stack of the detailViewController. Adjust the variable names to your situation of course.
Related
I have a navigation controller with a tableview inside on iphone version. Basically when I tap some row in this table A, sub-tableview controller A1 or A2 is pushed. Now on iPad, I need to show A1 or A2 in detailview in a splitview controller. How should I transform them? It's not in a root view controller.
I tried put my 'table A' view controller in master VC and a blank navigation controller in detail VC in the splitview, but how can I tell detail VC to show what after I select some row in table A?
Thanks...I tried but can't find any solution. I thought it would be pretty easy.
Have you looked at the template master-detail project that Xcode creates? It demonstrates the approach pretty clearly. Specifically have a look at the didSelectRowAtIndexPath: method of the masterViewController
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
NSManagedObject *object = [[self fetchedResultsController] objectAtIndexPath:indexPath];
self.detailViewController.detailItem = object;
}
}
Essentially your master view controller has a property that holds a reference to your detail view controller. This allows you to send a message to the detail view controller when it needs to display an object
In a split view controller app,how can I segue to different detail view controllers upon selecting a table row in the master view controller?
Just to be clear, I need the detail view controller to be replaced when I select a row in the master view controller. How do I wire up the view controllers? From the split view controller? or from the detail view navigation controller?
Implement tableView:didSelectRowAtIndexPath: in the master table view's delegate. Depending on the value of the indexPath parameter, call [detailViewController performSegueWithIdentifier:sender:] with the segue identifier of your choice.
In your tableView:didSelectRowAtIndexPath: method, do this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self performSegueWithIdentifier:#"YourSegueIdentifier" sender:self];
}
If you need to perform different segues based on the selected row, do this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *segueIdentifier = nil;
switch(indexPath.row) {
case 0:
segueIdentifier = #"YourSegueIdentifier";
break;
case 1:
segueIdentifier = #"ADifferentSegueIdentifier";
break;
.
.
.
}
if (segueIdentifier != nil) {
[self performSegueWithIdentifier:segueIdentifier sender:self];
}
}
// Get detail navigation controller
UINavigationController *detailNavigationController = [splitViewController.viewControllers objectAtIndex:1];
// Push the detail view controller
[detailNavigationController pushViewController:anyDetailViewController animated:NO];
// You also might need to set the splitview controller's delegate to this view controller
splitViewController.delegate = anyDetailViewController;
Use this code:
UINavigationController *detailNavigationController =[[[self splitViewController] viewControllers] objectAtIndex:1];
[detailNavigationController pushViewController:"your_view_controller" animated:YES];
In your segue, set your style to "Push", and your destination to "Detail". Current will push the destination view controller onto your Master view, whereas Detail will push it into the "Detail" view. It's that simple. Then wire it up the same way you wire everything else up.
But be careful, if you don't implement a way for it to wait for a previous segue, you can get an "Unbalanced calls" error if a new Controller is pushed onto the detail view before it's done dismissing/pushing another one. Double tapping a cell in a table will do it.
I have a simple test project. A UITableViewController (MasterViewController) embedded inside a navigation controller in storyboard. I am NOT segueing using the prepareForSegue to pass data to another view controller (DetailViewController). Instead, didSelectRowAtIndexPath is use to update a label in the detailviewcontroller as below:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
DetailViewController *detailViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"DetailViewController"];
NSMutableString *object = thisArray[indexPath.row];
detailViewController.passedData = object;
[self.navigationController pushViewController:detailViewController animated:YES];
}
Everything till this point works fine.
Now i have added another view controller in my storyboard. Made it the initial view controller, added two containers in it, then embedded both MasterViewController and DetailViewContainer in these containers.
Now instead of showing passed data inside the DetailViewController on the right side, its showing the passed data on the left side by replacing the controller view.
If i am not able to clarify what i am trying to say, here is the link to the project https://jumpshare.com/v/UiTFEB6AamIo8qX9sinW , its just for learning purpose.
Thanks
You're getting this problem because you are still doing this:
[self.navigationController pushViewController:detailViewController animated:YES];
The navigation controller you're referencing here is the one your master controller is embedded in, so you create an instance (different than the one that's already on screen) of detailController and push that onto the navigation controller.
What you want to do, is get a reference to the detail controller that's already on screen -- both child view controllers (the ones in the container views) are already instantiated when the app starts. So, you need to do this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
DetailViewController *detailViewController = [self.navigationController.parentViewController childViewControllers][1];
NSMutableString *object = thisArray[indexPath.row];
detailViewController.passedData = object;
}
This will pass the value to the detail controller, but you can't have the code to update the label in viewDidLoad, since that view is already loaded, and won't be called again. Instead, override the setter for passedData, and update the label there (note that I changed the name of the argument to passedInData, so it doesn't conflict with your property passedData):
-(void)setPassedData:(NSString *)passedInData {
passedData = passedInData;
detailDescriptionLabel.text = passedData;
}
Bu the way, unless you're planning on adding other controllers after your master view controller, there's no reason to have it embedded in a navigation controller at all, given this set up. If you take it out, then you need to remove the reference to self.navigationController when you get the reference to the detail controller. It would then just be:
DetailViewController *detailViewController = [self.parentViewController childViewControllers][1];
I have a storyboard with tabbarcontroller. One of tab bar has a tableview and I want that when the user tap in a row from tableview open a detail view. The problem is when I open detail view tab bar and navigation bar hides... In the storyboard I create the detail view as a new view controller, then I create a new file and referred it to the class of detail view .
The code in didselectrowatindexpath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
detalleYouTube *dvController = [[detalleYouTube alloc] init];
[self.navigationController pushViewController:dvController animated:YES];
}
Thank you in advance!
This is kinda old but if someone needs to do this here's an easy approach:
You can use add a segue from the view in the tab bar to detalleYouTube, put an identifier to the segue and do this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self performSegueWithIdentifier:#"segueIdentifier" sender:tableView];
}
Another approach to this is not to use tableView:didSelectRowAtIndexPath but instead use prepareForSegue:sender
the way I did it was:
-(void)prepareForSegue:(UIStoryboardSegue*)segue sender:(id)sender
{
DetailViewController *viewController = [segue destinationViewController];
CustomObject *custObject = [arrayOfObjects objectAtIndex:[self.tableView indexPathForSelectedRow].row];
viewController.objectNeeded = custObject;
}
This example is based on the idea that your detail view controller is connected to your table view controller.
I presume you have the 'Detail' view as part of the storyboard (not in a separate XIB), if so you will need to place a separate NavigationController at the start of the 'Detail' TabBarItem seque.
This page has a good tutorial on what I think your trying to achieve:
http://maybelost.com/2011/10/tutorial-storyboard-in-xcode-4-2-with-navigation-controller-and-tabbar-controller-part1/
Also check these links to a more in-depth Storyboard tutorial:
http://www.raywenderlich.com/5138/beginning-storyboards-in-ios-5-part-1
http://www.raywenderlich.com/5191/beginning-storyboards-in-ios-5-part-2
I am creating an app that uses a navigation controller.
In the the first view I have three different table views.
How can I make the tables open a new view in the navigation controller when one cell is selected?
Thanks
You implement tableView:didSelectRowAtIndexPath: as a delegate method on the view controller that shows the three table views, and in this method you initialize the new view controller you want to show and push it onto the screen by doing something like this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// TODO: Find out what view controller to push based on the tableView and the indexPath.
UIViewController *viewController = [[YourSpecialViewController alloc] initWithNibName:nil bundle:nil];
[[self navigationController] pushViewController:viewController animated:YES];
[viewController release];
}