xCode Master-Detail change detail viewcontroller from master viewcontroller - ios

I have just created a new "Master-Detail application" project I Xcode 5.
Then on my Master View Controller, I have change the table view to static, and added up a few items: Home, View 1, View 2.
I have removed the default databinding, so when i run it now it appears as intended.
As default my "Home" view is my Detail View Controller.
Now I would like: When i press "View 1" it changes my Detail View Controller to a new view I have created on my storyboard.
But how do I do that?
I have tried to push in my "View 1" but then i first have to go back to my Detail View, before I can get the menu to show up...
I guess I have to make my "View 1" the root controller?

I recommend you to use segues. You can setup them in storyboard with Interface Builder. Just remember to use replace segues instead of push:
And the code:
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
switch (indexPath.row) {
case 0:
[self performSegueWithIdentifier:#"mainSegue" sender:self];
break;
case 1:
[self performSegueWithIdentifier:#"sheduleSegue" sender:self];
break;
case 2:
[self performSegueWithIdentifier:#"mapSegue" sender:self];
break;
}
}
Besides it, you can do some additional setup for each segue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"mainSegue"]) {
TestViewController *dest = segue.destinationViewController;
dest.someNumber = 100500;
}
}

Related

Tab bar disappear after segue

After reading few topics in stack overflow about this problem, maybe someone will find where is my mistake: The tab bar in the destination controller disappear.
My source view controller is a Table view controller. when clicking on the cell There is a segue to Navigation view controller that linked to the destination view controller.
The segue is modal.
Table View Controller:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"cell selected");
//doing some thing and call to the segue..
[self performSegueWithIdentifier:#"fromSearchToProfileSeg" sender:nil];
}
And the prepareForSegue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"fromSearchToProfileSeg"]){
///searchVC.username = self.username;
NavViewController *navigationController = segue.destinationViewController;
ProfileViewController *pro = (ProfileViewController * )navigationController.topViewController;
pro.username = self.username;
}
}
And it's Look like:
Unfortunately, When clicking on the cell, the segue is working and the destination view controller is open, but the tab bar disappear. Does anyone know where is the mistake?
Make sure you don't have the option "Hide Bottom Bar on Push" in the attributes inspector for that view controller.

How do I segue to different detail view controllers?

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.

performSegueWithIdentifier on didSelectRowAtIndexPath

With this code every time user click on any cell will perform the segue again and again , I am wondering how could I keep track of the loaded view to keep data when switching views and not an infinite new viewcontroler.
Thanks -
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == 0) {
[self.navigationController
performSegueWithIdentifier:#"rep" sender:self];
} else if (indexPath.row == 1) {
[self.navigationController
performSegueWithIdentifier:#"rep1" sender:self];
}
}
Try my other approach first, but if you really need a maintain a pointer to the new view controller you could try this approach. This should perform the segue once, creating the reference to the view controller which will subsequently be manually pushed into the navigation controller.
Override the view controller methods:
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender{
if(self.myViewController == nil){
return YES;
}else{
[self.navigationController pushViewController:self.myViewController animated:YES]
}
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
self.myViewController = (MyViewController*)segue.destinationViewController;
self.myViewController.customVar = 1; //perform initial customization
}
What do I know though, I've never used Storyboards...
Perhaps an alternative to maintaining a reference to the view controller would be to customize the view controller prior to seque.
Override the view controller method:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
MyViewController *targetController = (MyViewController*)segue.destinationViewController;
targetController.customVar = 1;
}
The default implementation of this method does nothing. Your view controller overrides this method when it needs to pass relevant data to the new view controller. The segue object describes the transition and includes references to both view controllers involved in the segue.
You don't need to take new View controller each and every time for each row unless and until you want it customized. This will make large amount of view controllers on storyboard.
So, Just command drag segue from controller A to B. Example: if A is tableViewController and B is simple VC where you are displaying data of table's row then command drag from whole tableViewController to B. Now this will act as common segue with one identifier only.
So in your code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//Set your B's label/property etc to cell's data or anything so that it will reflect in B.
B.label = cell.text;
[self performSegueWithIdentifier:#"Identifier" sender:self];
}
Hope this helps.
I think you can keep the new viewController's pointer. Then next time you can use it like this:
[self.navigationController pushViewController:thePointer animated:YES]
I very seldom use Storyboard. So I am not sure it will work.

Storyboards and programmatically views

I'm totally lost in this issue. I have been working with storyboards, I have created a navigation controller with tableviews and some stuff. There are Services in each row of the tableview and I need to create one detail view for each service.
There are a lot of services, so I can't create them in the storyboard. The idea is to download the Services from a webservice (number of parameters, types of each one, etc..) and add as textfields / buttons as appropriate to the Service.
So, my problems and questions are:
1) Can I combine Storyboards and views programmatically? When I create a NewView in MyTableviewClass, should I do it in my prepareforsegue method? How can I show it in the screen without loosing my navigation controller? this is what I have (it doesn't work: it says to me that there is no segue with name 'Service1' ) :
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
if ([[segue identifier] isEqualToString:#"NextLevel"]) {
[segue.destinationViewController setActualNodo:[actualNodo getSonAtIndex:indexPath.row]];
} else if ([[segue identifier] isEqualToString:#"Service1"]) {
CGRect bounds = self.view.bounds;
UIView *myview = [[UIView alloc] initWithFrame:bounds];
[myview setBackgroundColor: [UIColor redColor]];
[self.view addSubview:myview];
[self.view bringSubviewToFront:myview]; }
Any book or reference is welcomed but I couldn't find anything similar. Is this very complicated in iOS? I have done a similar thing in Java. I have read about generating interfaces dynamically with XIBs but, sincerely, I don't know what it is..
Thanks for all.
Yes you can create a StoryBoard with a view and then add views programmatically to it.
You should not try creating a view within your prepareForSegue method. This really should be used for passing objects to another ViewController.
I would suggest this to you. Go back to your StoryBoard and create a new UIViewController scene. Click on your first scene and CTRL drag to the new scene. Next, click on your segue and give it a name.
Step 1:
Create a new class called ServicesViewController and make sure it's a subclass of `UIViewController:
Step 2:
Go back to your StoryBoard and click on scene so that it is selected. Next, click on the Files Owner and finally click on the class info button (the third button) and finally select your ServiceViewController class you just created.
Step 3:
Back in your ServicesViewController in the didSelectRowAtIndex method call your seque:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self performSegueWithIdentifier:#"YOUR_SEGUE_NAME" sender:nil];
}
For now, clean out all the code in your prepareForSegue method and just get the transition down first.
In addition to Flea's answer, if you need to keep the navigation controller, just create a push segue in your storyboard by control dragging from the file owner icon (the yellow box under your view controller's view) of the table view controller to the ServiceViewController you added to the storyboard, this should show a popup window where you can select "push" as the type of the segue. Next, select the segue and in the attribute inspector (the fourth button, next to the one in the snapshot) and in the "Identifier" text field type in a unique identifier for your segue, such as serviceSegue.
At this point, using Flea's code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self performSegueWithIdentifier:#"serviceSegue" sender:nil];
}
And in the code you posted:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
if ([[segue identifier] isEqualToString:#"serviceSegue"])
[segue.destinationViewController setActualNodo:[actualNodo getSonAtIndex:indexPath.row]];
}
I'm not sure what you are trying to do with the other segue "Service1", but if you want to change the view of the TableViewController, segues are not the way to do it. If anything you should do it in the didSelectRowAtIndexPath method depending on the row selected:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (You want to transition to other view controller)
[self performSegueWithIdentifier:#"serviceSegue" sender:nil];
else
Change your view here.
}
I hope this helps!
It sounds like you just have multiple cells in a tableView. Instead of using segues you can simply create different cells with different identifiers and show or hide them based on what services are detected in your services array which is populated from your web service.

How to open view controller from didSelectRowAtIndexPath within storyboard?

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

Resources