I’m trying to build a group messaging app with Parse. I would like to use storyboards only because I am new to iOS.
The first screen is a UITableViewController with a list of groups.
The second screen is a PFQueryTableViewController that inherits from UITableViewController with a list of messages for that group.
I would like to add a chat box(UITextField) to the PFQueryViewController, but I can’t seem to do that because it is a UITableViewController.
From what I can tell in order to add a chat box I need to use a UIViewController and manually add a table view. Then resize the table view to allow for a chat box at the bottom.
The problem is then PFQueryViewController inherits from a UITableViewController and not a UITableView.
I am using this to pass the selected group PFObject to the new PFQueryViewController.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
[self performSegueWithIdentifier:#"detail" sender:nil];
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
if([[segue identifier] isEqualToString:#"detail"])
{
NSIndexPath *ip = [self.tableView indexPathForSelectedRow];
PFObject *passObj = [self.objects objectAtIndex:ip.row];
PFQueryTableViewController *messageDetail=[segue destinationViewController];
[messageDetail setReceiveObj:passObj];
messageDetail.hidesBottomBarWhenPushed = YES; //Hide Tab Bar
}
How can I use PFQueryViewController as a subview of UIViewController and pass the PFObject to that controller?
*I don't have enough reputation for images
I'm, unfamiliar with the Parse framework but you should be able to use View Controller Containment to achieve this.
Here is a nice guide to check out.
Here is the relevant part for adding the view of a view controller as a subview in another view controller:
// put this in viewDidLoad
[self addChildViewController:_pfQueryController]; // 1
[self.view addSubview:_pfQueryController.view]; // 2
[_pfQueryController didMoveToParentViewController:self]; // 3
Related
UIViewController appears as black screen when handling programmtically
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *user = (NSString *) [self.friends objectAtIndex:indexPath.row];
ChatViewController *chatController = [[ChatViewController alloc] initWithUser:user];
[self presentModalViewController:chatController animated:YES];
}
This below given code is in the chatviewcontroller
- (id) initWithUser:(NSString *) userName {
if (self = [super init]) {
chatWithUser = userName;
}
return self;
}
and when i do it using storyboard segue then only tableview row gets selected but doesn't shows ChatViewController
else if ([segue.identifier isEqualToString:#"showChatView"]) {
ChatViewController *viewController = (ChatViewController *)segue.destinationViewController;
viewController.chatWithUser = friends;
}
If anyone can figure out what i m doing wrong. Will appreciate so much.
Thanks for help though.
presentModalViewController:animated: is deprecated (since iOS 6), you should use presentViewController:animated:completion:
However, it looks like you are using a segue to get to your ChatViewController, so you shouldn't even have to present the view controller since this is handled by Interface Builder. If your segue is set up correctly, replace presentModalViewController:animated: with [self performSegueWithIdentifier:#"showChatView" sender:nil];
EDIT
You should just move your ChatViewController setup to the prepareForSegue:sender: method, like so:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *user = (NSString *)[self.friends objectAtIndex:indexPath.row];
[self performSegueWithIdentifier:#"showChatView" sender:user];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showChatView"]) {
NSString *user = (NSString *)sender;
ChatViewController *chatVC = (ChatViewController *)[segue destinationViewController];
// No need to have an init method with the user property since Interface Builder does that for you.
chatVC.chatWithUser = user; // Expose this property in ChatViewController's header file if it's not already
}
That should be all you need to do in your code.
Presenting Versus Showing a View Controller
The UIViewController class offers two ways to display a view controller:
The showViewController:sender: and showDetailViewController:sender: methods offer the most adaptive and flexible way to display view controllers. These methods let the presenting view controller decide how best to handle the presentation. For example, a container view controller might incorporate the view controller as a child instead of presenting it modally. The default behavior presents the view controller modally.
The presentViewController:animated:completion: method always displays the view controller modally. The view controller that calls this method might not ultimately handle the presentation but the presentation is always modal. This method adapts the presentation style for horizontally compact environments.
The showViewController:sender: and showDetailViewController:sender: methods are the preferred way to initiate presentations. A view controller can call them without knowing anything about the rest of the view controller hierarchy or the current view controller’s position in that hierarchy. These methods also make it easier to reuse view controllers in different parts of your app without writing conditional code paths.
Refer this link to know about what is the difference between segue programmatically and using interface builder. I hope it is helpful.
#timgcarlson's answer is great for solving your problem.
As per #Sneha's suggestion I have added a paragraph that feel is useful.
this is my problem. I can perfectly show a detailedViewController came from a table view, but i got 2 more tableview that i want to make it seem in detailed.When i gave it same variables - since every things that came same - it still doesn't go to the next view controller.I checked segue identifier aswell and i really don't want to make a new detailed controller.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"showDetail"]) {
// Get destination view
detailViewController *destViewController = [segue destinationViewController];
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSInteger tagIndex = [(UIButton *)sender tag];
destViewController.recipeName =[[self.content objectAtIndex:indexPath.row] valueForKey:#"recipeName"];
destViewController.recipeDetail =[[self.content objectAtIndex:indexPath.row] valueForKey:#"recipeDetail"];
this is how i pass the data.They are exactly same with a small difference. The content of the content array.
You can go to the same view controller from multiple other controllers. You may be able to do this by simply creating the segue from the appropriate cells in each table. The way I've done it is to create a segue from each table view controller to the "detail" view controller, and then perform the segue in code when the appropriate cell is selected. Keep in mind that when creating segues in IB, there is a difference between creating them from table view cells and from the view controllers themselves.
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.
I have a Master-Detail application.When the user selects a row in the MasterTable, I want to open another Table (not the DetailViewController). It should paper besides the MasterViewController, similar to the Facebook app on iPad.
I have a Custom segue from the MasterViewController to this table (DocumentViewController of type UITableViewController). This DocumentViewController is 'Embedded' in a navigation controller.
In short, the items on my storyboard look like this:
navigationController->MasterViewController->navigationController->DocumentViewController.
The segue is from MasterViewController to navigationController.
Do I have to perform the segue in "didSelectRowAtIndexPath"? Or do I have to use "performSegueWithIdentifier" in didSelectRowAtIndexPath?
If I understand your question correctly, the segue should be from MasterViewController to DocumentViewController. Make sure to give it a unique identifier, and then reference what you want to do in the prepareForSegue in your MasterViewController.
Example:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"showList"]) {
// gets indexPath for the currently selected row in my UITableView
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
// pull back some useful data from Core Data according to what was selected in my UITableView.
NSManagedObject *object = [[self fetchedResultsController] objectAtIndexPath:indexPath];
// listDataItem is a property of the controller (in this case a UITableViewController)
[[segue destinationViewController] setListDataItem:object];
}
}
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