How to initialize popover view from UICollectionViewCell in IOS - ios

I've been tracking along with an iPad app using storyboards, and I've been stuck on this for days. How can I initiate a popover segue by selecting a cell in a collection view? The main problem is getting past the error that the popover must be anchored to a view.
The approach seems to be putting a dummy popoverAnchorButton (hidden, disabled) in the view, create a segue from it to the popover view in the storyboard, position it in didSelectItemAtIndexPath, and then [self performSegue]. Code looks like this:
- (IBAction)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
[self.collectionView deselectItemAtIndexPath:indexPath animated:NO];
UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:indexPath];
CGRect anchorRect = CGRectMake(cell.center.x, cell.center.y, 1.0f, 1.0f);
self.popoverAnchorButton.frame = anchorRect;
[self performSegueWithIdentifier:#"popoverSegue" sender:self];
}
This works elsewhere in the app in a table view, because the storyboard lets me drop a button in the view, to use as an anchor point. But Xcode doesn't let me drop a button or any other suitable view into the collection view in the storyboard, so I can't create the segue. Creating the button programmatically is no help, because I can't build a UIStoryboardSegue from it, and any manual segue from the controller gives the same error about lacking an anchor point. Any ideas?
I think another path could be to skip segues and instantiate the popover view controller programmatically, but the roadblock here is an error stemming from the fact that the popover view I create (since I'm using storyboards) has no xib. Do I have to create a separate xib file just for this popover view? Is that the only option?

If you are interested in getting the CGRect of the currently selected cell in the collection view you might use:
CGRect rect = [collectionView layoutAttributesForItemAtIndexPath:indexPath].frame;
And after that you can display your popover from that rect using presentPopoverFromRect:inView:permittedArrowDirections:animated: of your UIPopoverController.
And yes, you can always dynamically load a VC from your storyboard if it has a storyboard identifier associated to it:
UIStoryboard* storyboard = [UIStoryboard storyboardWithName:#"YourStoryboardName" bundle:nil];
UIViewController* vc = [storyboard instantiateViewControllerWithIdentifier:#"YourIdentifier"];
In case you are calling the code from a VC loaded from storyboard itself, instead you can use:
UIViewController* vc = [self.storyboard instantiateViewControllerWithIdentifier:#"YourIdentifier"];

Related

Popover segue not working

I am developing one iPad application using storyboard. In my application i have 2 view controllers(First view controller and Modal view controller). In my first view controller I have one table view with cell containing one button. If I click the button in each cell I need to go to modal view controller. I connected the modal view controller and button by using a segue. Segue is working perfectly when style is modal but I need style Popover. When I am trying to change the segue style popover the storyboard error occurs and compilation failed comes. How can I solve this issue.
Follow the steps in the image. hope I will help you.
If the error is "Couldn't compile connection..." the problem is how XCode handles an outlet inside a dynamic table cell view.
I suggest you 2 alternatives:
1) The error doesn't come if you can use a "static" table view, in this way the table view must live inside a UITableViewController.
2) If you need a dynamic table, subclass the cell view and in your class (say MyUITableCellView) put an outlet:
#property (weak, nonatomic) IBOutlet UIButton *segueButton;
Then in your storyboard create an outlet from the prototype cell (of class MyUITableCellView) to the button inside the cell (do not create the segue in the storyboard, create only the destination view controller).
Then in the "cellForRowAtIndexPath" do the following:
MyUITableCellView *cell = (MyUITableCellView*)[tableView dequeueReusableCellWithIdentifier:#"MyCell"];
/* IMP: Here you should check if button has already this action (reused) */
[cell.segueButton addTarget:self action:#selector(showPopover:) forControlEvents:UIControlEventTouchUpInside];
and then add the action:
- (void)showPopover:(UIButton*)sender
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *secondVC = [storyboard instantiateViewControllerWithIdentifier:#"secondVC"]; // this is the storyboard id
self.popover = [[UIPopoverController alloc] initWithContentViewController:secondVC];
CGRect fromRect = [self.view convertRect:sender.frame fromView:sender.superview];
[self.popover presentPopoverFromRect:fromRect inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
Hope this has helped.
Have you included the <UIPopoverControllerDelegate> and implemented it? That's easy to forget the first times.
May be you might have not connected the Anchor, put UIView in your Viewcontroller view somewhere with background colour clear and set Anchor point of the Segue to that view.....

UITableViewController static cells not appearing when pushed to navigationController

I'm running into a rut...
I've create a UITableViewController with static cells (i've deleted all default UITableView methods). Whenever I segue to this view controller, the static cells appear, but when I push it onto the navigationcontroller the static cells do not appear...any idea to why this would be hapenning?
Here is my code:
//shows empty uitableviewcontroller
OthersUsersTableViewController *tvc = [[OthersUsersTableViewController alloc]init];
[self.navigationController pushViewController:tvc
animated:YES];
and
//works
[self performSegueWithIdentifier:#"toOtherUser" sender:self];
Thanks for the help!
If you manually alloc and init your Static table view, how should your app know that it is referencing a static table view in your storyboard?
Give your static table view an Identifier in the storyboard and initialize it like this:
OthersUsersTableViewController *tvc = [self.storyboard instantiateViewControllerWithIdentifier:#"staticTableView"];
You can set your identifier in the menu on the right where you also set the custom class for the view controller. The field is called Storyboard ID.
when you're just calling [[UIViewController alloc] init], the UI objects you've added and configured on the storyboard,does not get called or wired to your view controller.
You should instantiate the view controller through the storyboard itself by adding an identifier to your view controller(on the storyboard) and calling instantiateViewControllerWithIdentifier method of your storyboard.
You can get a reference to your storyboard through the current view controller's storyboard property.
OthersUsersTableViewController *tvc = [self.storyboard instantiateViewControllerWithIdentifier:#"identifier"];

Push view of storyboard in accessorybutton tapped

I have storyboard named "MainStoryboard_iPhone.storyboard" and it has 2 views. The first view has a table cell with disclosure button. I can drag drop the table cell to other view and show the view, but I need to do it programmatically only when user click on accessory button without using segue. The name of 2 views are RootViewController and ProviderLookupViewController. Currently I have tried this code but doesnt work, it throws error when I click on the accessory button on the cell. Commented lines are the other things that I tried
-(void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
UIStoryboard* sb = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone"
bundle:nil];
// ProviderLookupViewController* vc = [sb instantiateViewControllerWithIdentifier:#"ProviderLookupViewController"];
UIViewController* vc = [sb instantiateViewControllerWithIdentifier:#"ProviderLookupViewController"];
[self presentModalViewController:vc animated:YES];
//[self.navigationController pushViewController:vc animated:YES];
}
If I am correct:
1) From your question it seems that you have a story board with two view controller, the first one is a UITableViewController and the other a subclass of UIViewController.
2) You want to present the second view when the user clicks the disclosure button.
Given that you use a storyboard instead of nib files, I recommend that you use a segue, it will solve you problem without writing code.
A table view cell can have two segues, one if you select the cell and another if you select the accesory button. Control drag from from the accessory button to the second view controller instead of doing the control drag from the cell and when the menu appears you have to select an option below Accesory action instead of below Selection Segue
The prototype cell of the table view has to have the disclosure accessory enable. Do it from the utilities pane (the right one). Accessory can't be none do this. In the picture accessoy is Detail disclosure.
The utilities pane also let's you do the segue. Use accessory action, though, teh picture is from one of my projects.
First give storyboard id as ProviderLookupViewController in your scenario and tick use storyboard Id then
ProviderLookupViewController* vc = [self.storyboard instantiateViewControllerWithIdentifier:#"ProviderLookupViewController"];
[self presentModalViewController:vc animated:YES];
Note:ProviderLookupViewController is your identifier.
Create a segue in IB from one view controller to another. Add some identificator to segue and just use
[self performSegueWithIdentifier:#"SomeSegueName" sender:someObject];

Storyboard Segue From View Controller to Itself

I am trying to make a mechanism to drill down a file / folder list. The idea is to show the same file list view controller every time the user selects a folder, and show a file detail view controller if he/she selects a file.
So far, I have created a segue from the file list view controller to the file detail view controller, and a segue from the file list table view cell to the the file list table view controller:
The issue with this is that as soon as the user taps the cell, the segue is executed. I would like to remove the segue from the table view cell and make one from the file list view controller to itself. That way, I could trigger the right segue programmatically when the user tapped the cell.
So, my question is: Is it possible to create a segue from a view controller to itself in Interface Builder?
If you are using a navigation controller you need to push the ViewController into the nav stack. In this example, i named my ViewController "VDI" in my Storyboard ID setting.
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle: nil];
YourVC *dest = [storyboard instantiateViewControllerWithIdentifier:#"VDI"];
[self.navigationController pushViewController:dest animated:YES];
If you don't want the NavigationController to keep adding itself into your "Back" history you can pop the stack before adding to it like so.
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle: nil];
YourVC *dest = [storyboard instantiateViewControllerWithIdentifier:#"VDI"];
UINavigationController *navController = self.navigationController;
[navController popViewControllerAnimated:NO];
[navController pushViewController:dest animated:YES];
Using Xcode 5 there is a much simpler solution.
Click the table cell in the storyboard
Open the Connections Inspector (right arrow icon in the upper right)
Under "triggered segues" you see "selection"
Drag from the circle next to "selection" to the cell in the storyboard
That's it.
I developed a method to create a segue using a phantom button. I believe it will solve your problem. You can read about it in my answer here.
Instead of performing a segue to the same controller, you can instantiate a view controller (the same one) from storyboard, and then push that onto the navigation controller.
Interface Builder approach: Just segue to a storyboard reference which refers back to the presenting view controller.
The correct answer is to use a Storyboard Reference that is referencing the UIViewController you want to segue to itself and then point the segue at it.
In IOS 6, there is a cleaner solution than using a phantom button. You can still define the segue from the table cell to the view controller, and look at the sender to cancel the automatically triggered segue:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//storyboards should use segues and override prepareForSegue instead
//but here we need custom logic to determine which segue to use
id item = [self.fetchedResultsController objectAtIndexPath:indexPath];
if (item meets condition) {
[self performSegueWithIdentifier:#"segue1" sender:self];
} else {
[self performSegueWithIdentifier:#"segue2" sender:self];
}
}
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender {
//ignore segue from cell since we we are calling manually in didSelectRowAtIndexPath
return (sender == self);
}
Here's how you can push another instance of the current view controller without defining a segue or hardcoding its own identifier:
SameViewController *same = [self.storyboard instantiateViewControllerWithIdentifier: self.restorationIdentifier];
[self.navigationController pushViewController: same animated: YES];
You just need to set the Restoration ID to be the same as Storyboard ID (there's a checkbox for that in IB).
Hope this helps.
I found that you can create multiple prototype cells.
Than you can link every cell (in the Storyboard) to a different View.
Something like this:
NSString *CellIdentifier = #"Cell";
if (Condition2 ){
CellIdentifier = #"Cell2"; }
if (Condition3 ){
CellIdentifier = #"Cell3"; }

IOS Switch view and storyboard not works

I have a problem with switching views. I'm using a simulator with xcode 4.2
Storyboard contains:
NavigationController (initial view controller)
UIViewController which has relationship with the navigation controller
UIViewController (paired with my custom class: ViewEntryImageController) which hasn't got any relationship. Contains a button, a bottom toolbar with some toolbar button.
User come into the UIViewController, where he can see a ScrollView and in ScrollView some images.
Images has a gesture:
UITapGestureRecognizer *recognizer=[[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(openEntryImage)];
[image addGestureRecognizer:recognizer];
[recognizer release];
The openEntryImage function:
(IBAction)openEntryImage
{
ViewEntryImageController *controller=[[ViewEntryImageController alloc]initWithNibName:nil bundle:nil];
controller.modalTransitionStyle=UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:controller animated:YES];
[controller release];
}
When I try to tap the image, the openEntryImage works as well (the effect is correct), but I don't see my ViewEntryImageController view and my buttons, I'm only see a black window.
I try to put a NSLog line into the ViewEntryImageController viewDidLoad function, and it works, so what is the black window and where is my view controller?
When I try to use pushViewController, on the new view I found a navigation toolbar with a back button, but no other controls.
I tried another version, I created a UIViewController class, but now with a xib file. I used it instead of ViewEntryImageController and it works. Why?
I want to use this controller in storyboard too.
The ViewEntryImageController class by itself has no information about how to build the dialog. But you can instantiate your view controller on your own from the storyboard:
UIStoryboard *myStoryboard = [UIStoryboard storyboardWithName:#"StoryboardFileName" bundle:nil];
ViewEntryImageController *controller = (ViewEntryImageController *)[myStoryboard instantiateViewControllerWithIdentifier:#"ViewEntryImage"];
This assumes a storyboard name of StoryboardFileName and that the view entry image controller has an identifier of ViewEntryImage set in the view properties (Attributes inspector, section "View Controller").
Try it like this :
ViewEntryImageController *controller=[[ViewEntryImageController alloc]initWithNibName:#"ViewEntryImageController" bundle:nil];
If you don't use .nib names but rather use storyboards, it's a bit harder. Create a segue from the controller to the ViewEntryImageController controller by holding ctrl and dragging from one view to the other. Click this segue and give it an identifier.
Then use the [self performSegue:#"identifier"]; function to present the next view.

Resources