Dismiss UITableViewController on tableView:didSelectRowAtIndexPath:indexPath - objective-c

Currently I have a UIView with a UItableview cell added to the subview, like so,
When the button is pressed, it pushes to another navigation controller whos subclass is a uitableviewcontroller....
So When the user clicks on one of these tableviewcells... I want the viewcontroller to be poped from the navigation stack and go back to the previous view that is listed first.
I implemented the UITableviewcontroller method listed below with the following implementation.... but nothing occurs :P....
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self dismissViewControllerAnimated:YES completion:nil];
}
Any ideas?

If you are pushing the view controller onto the navigation controller's stack i.e. pushViewController:animated:, you should pop out current view controller using popViewControllerAnimated: method.
If you want to go to a view controller not just one level below the current view controller (or top view controller in UINavigationController's jargon), you can use popToViewController:animated:. And to go to the root view controller of the navigation controller, use popToRootViewControllerAnimated:.
But if you are presenting a view controller modally i.e. presentViewController:animated:completion:, then only you use the dismissViewControllerAnimated:completion: method to dismiss the presented view and go to the presenting view controller.

Related

How do I present a UIViewController modally when a button on it's parent view controller is tapped?

I'm having a little issue with an app I've completed. The problem is with a search view controller presented modally.
I have a search button that when tapped presents the SearchViewController modally.
I have 3 different controllers it can be presented from.
MainViewController > CollectionViewController > DetailViewController
This is actually how the controllers are in the hierarchy.
The results are always displayed on the collection view controller. Basically the collection view is refreshed and the remaining cells show are the result of the search.
Searching from collection view controller:
In the collection view controller, when the search is tapped. The search view controller is presented modally. Search text is entered and a list of matches is shown. When a row is tapped then the search view controller is dismissed and notifies the collection view controller using delegation the collection view is them refreshed with the results.
Searching from detail view controller:
In the detail view controller, when the search is tapped. The detail view controller is popped off the stack revealing the collection view controller. I use delegation to notify the collection view controller that the detail view controller was popped of the stack after the tap of a search button. Immediately the search view controller is opened making it possible to search as if we originally presented the search view controller from the collection view controller.
My issue arises when trying to search from my main view controller. Right now things are working but it doesn't have a very professional feel to it. Let me explain.
To get search working from my main view controller I use delegation. So in the method connected to the search button I perform this segue:
- (void)searchButtonTapped
{
[self performSegueWithIdentifier:#"garmentsCollectionSegue" sender:nil];
}
The protocol is defined in my interface file:
#class VAGMainTableViewViewController;
#protocol VAGMainTableViewControllerDelegate <NSObject>
- (void)mainTableViewControllerDisappearedwithTitleForObject:(NSString *)titleString;
- (void)searchButtonOnMainTableViewControllerTapped;
#end
#interface VAGMainTableViewController : UITableViewController
#property (nonatomic, weak) id<VAGMainTableViewControllerDelegate> aDelegate;
In my preparation before segue I have this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
[self setADelegate: [segue destinationViewController]];
[[self aDelegate] searchButtonOnMainTableViewControllerTapped];
}
Here I set the delegate and also make a call to the delegate method, making the collection view controller aware of the button tap in my main view controller.
Finally in my collection view controller when the tap is detected a call to the method that presents the search view controller modally is made. Search view controller is presented.
In collection view controller
- (void)searchButtonOnMainTableViewControllerTapped
{
[self searchButtonTapped];
}
- (void)searchButtonTapped
{
VAGSearchViewController *svc = [[self storyboard] instantiateViewControllerWithIdentifier:#"searchPageSB"];
svc.delegate = self;
[self presentViewController:svc animated:NO completion:nil];
}
The search view controller notifies the collection view controller it was dismissed using delegation. This is when the querying and refresh of the collection view controller is done and the result of the search is shown.
- (void)searchViewControllerDismissed:(VAGSearchViewController*)searchViewController withTitleForObject:(NSString *)titleString
{
_searchTitleString = titleString;
[self setObjects:nil];
[self performQuery];
}
Ok so this works but it doesn't look professional because for a split second after the push to the collection view controller from the main view controller the collection view is shown before the search view controller is presented.
The feel I'm aiming for is a snappy one. So I'd prefer if the search view controller would be presented instantly.
Hopefully my detailed post give you an idea of what I'm doing.
There is a much more efficient way to do this. The problem is I can't figure it out.
Would appreciate some help
Thanks for your patience
You can do one thing did not push Collection view controller when search button is tapped.
After pushing modalviewControler if search done then you Call the delegate in MainviewController and Then push collection Viewcontroller with no animation in DelegateMethod. its look what you want

Does presentModalViewController: add the view controller to the stack?

I have a main navigation controller with a root view controller. In the root view controller, on the push of a button I present second view controller like this:
SecondVC *secondVC = [[SecondVC alloc] initWithNibName:#"SecondVC" bundle:nil];
[self.navigationController presentModalViewController:secondVC animated:YES];
In the second view controller, on the push of an other button, I want to present a third view controller (this time from a Storyboard):
ThirdVC *thirdVC = [[UIStoryboard storyboardWithName:#"Settings" bundle:nil] instantiateInitialViewController];
[self.navigationController presentModalViewController:thirdVC animated:YES];
However this doesn't do anything. I debugged and it turned out, that self.navigationController is nil.
Shouldn't it be the main navigation controller? Or doesn't presentModalViewController: add the view controller to the stack? Do I always have to put a view controller in a navigation controller before presenting id modally?
The new view controller SecondVC is being presented modally, and it's not added to the view controller stack of the navigationController. You need to create a new UINavigationController, and put SecondVC inside the navController before presenting it modally.
You'll need to add something like:
UINavigationController *navControl = [[UINavigationController alloc] initWithRootViewController:secondVC];
[self addChildViewController:navController];
[self.navigationController presentModalViewController:secondVC animated:<#(BOOL)#>]
your view controller while being presented is not inside a navigation controller. And will not have access to the presenting controllers navigation controller.
Furthermore if you push or pop stack items on the navigation controller beneath the modal view controller you will likely not notice anything.
If you want to put the controller in the stack you can alternatively show the view controller yourself.
[self.view addSubView:myViewController.view]
myViewController.view.frame = self.view.bounds;
and to dismiss the view controller you would simply remove it from its superview.
the drawback here is that some of the did and will appear methods are not called on the view controller. Therefore you may want to call them yourself.
But the principal is much the same. And you can easily simulate the presenting animation with the animation system.
Give it a starting point below your form, then start your animation block and put the view.frame to superview.bounds also giving it an animation time. I find that 2 seconds is ok. sometimes less.
at this point the presented view is inside the controller which is on the stack. Now while you cant directly modify the navigation controller within the presented view controller you could set a delegate that tells the original your intentions and therefore the presenting view controller (the one on the navigation stack) can push or pop the view controllers as requested. And the presented view controller will be pushed along with it.
Another positive point is that you can do much like other apps do, and present a semi modal view. With a partially transparent background. this way you can show things happening behind the view even tho they dont directly manipulate it.

Pushing a navigation controller is not supported- performing segues

I created a new navigation controller in my storyboard (not programmatically!) and set it to be "Root View Controller" to a regular UIViewController and added a button in it which says- forward to the next view controller (this second view controller is a view controller which I want that will have a back button to link to the initial view controller).
Now, whenever I try to link the button to the next view controller- "Pushing a navigation controller is not supported".
Help me please, and thanks
EDIT:
I accidentally subclassed UINavigationController, and not UIViewController in my class.
Thank you anyway.
I've tried this and have no problems, its all done in IB with no additional code required ...
Start a new project, "Single View Application" using story boards
Select storyboard and delete the views its produced.
Drag on a new Navigation Controller (it will bring a table view with it)
Delete the table and the table view controller, so you are just left with the Navigation Controller
Drag on a normal view controller
Right Click and drag from the Navigation controller to the new View and choose "Relationship - Root View Controller"
Drag a "Bar Button Item" on to the Navbar which should be visible on the top of your ViewController, you can rename this Forward if you wish.
Now drag on another view controller which is the one your "Forward" button will push in to view.
Right Click and drag from the bar button to the 2nd View Controller, and choose "Push"
Run the project and you will get a Single view with a Navbar and your button, clicking your button will Push the other view and give you a Back Button to return to the first View Controller. I'll try and post a picture of my storyboard if it helps.
Plasma
I had the same trouble. I wanted to have a navigation controller on each storyboard, so that each could run independently, be individually debugged, and so that the look would be right with the navigation bar.
Using other approaches, I found the UINavigationController would be retained from the original storyboard -- which I didn't want -- or I'd get errors.
Using the AppDelegate in your view controller to set the rootViewController worked for me (borrowing segue naming conventions from Segue to another storyboard?):
- (void)showStartupNavigationController {
NSLog(#"-- Loading storyboard --");
//Get the storyboard from the main bundle.
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:#"Startup" bundle:nil];
//The navigation controller, not the view controller, is marked as the initial scene.
UINavigationController *theInitialViewController = [storyBoard instantiateInitialViewController];
NSLog(#"-- Loading storyboard -- Nav controller: %#", theInitialViewController);
//Remove the current navigation controller.
[self.navigationController.view removeFromSuperview];
UIWindow *window = [(AppDelegate *)[[UIApplication sharedApplication] delegate] window];
window.rootViewController = theInitialViewController;
To swap views Programatically you would need to select the segue and give it an Identifier like "PushView" then call it like this ....
[self performSegueWithIdentifier:#"PushView" sender:self];
That will programatically do the same as clicking the forward button. I've created you an example project with the code discussed above. Has an -(IBAction) with code in you can use for programatially changing the view.
PushView.zip
I also wanted to do this, present a screen (that had an embedded navigation controller) when the user pushes a button.
At my first attempt, I connected the segue from the button in the fist screen to the Navigation Controller, and the app was crashing with this error "Pushing a navigation controller is not supported".
This is the solution I found:
Select the segue from the button in the first screen to the navigation controller.
If it had an identifier, copy its name. Then delete that segue.
Then create a new segue by CTRL-clicking the button in the first view controller and dragging to the VIEW CONTROLLER YOU WANT TO PRESENT (not to the Navigation Controller that is pointing at it), and select Push in the small pop up window.
Then click the icon in the middle of the segue and paste the name you copied in the first step as an identifier for it.
IB is going to give you a warning "Scene is unreachable due to lack of entry points and does not have an identifier for runtime access via -instantiateViewControllerWithIdentifier:." Don't worry, it works perfectly.
If you want to customize the string that is shown as the Back button to return, you can add this line in the viewDidLoad method OF THE VIEW CONTROLLER THAT IS BEING SHOWED AFTER THE BUTTON IS PRESSED, that is the Child view controller.
(replace "Settings" with the name you need)
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationController.navigationBar.topItem.title = #"Settings";
...
}

UISplitViewController not calling delegate methods while pushing new detailView

I setup a storyboard based on the Master-Detail Application, embed the detail view in a navigation controller, and add a new table view controller object which I will use as a second detail view controller.
I then push the new detail view controller with the following code (instead of a segue because I am pushing both a root view and a detail view controller at the same time. Only the detail view code is shown).
// Push the detailView view controller:
NewClass *newViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"test"];
newViewController.navigationItem.hidesBackButton = YES;
self.splitViewController.delegate = newViewController;
[self.detailViewController pushViewController:newViewController animated:YES];
This works perfectly, EXCEPT that the splitView delegate methods are never called before or after the push. If I do this while in portrait mode, after it pushes the detailViewController, the button to drop down the masterView popover does not show up UNTIL I rotate to landscape mode and then back to portrait mode.
How can I cause the willHideViewController/willShowViewController split view controller delegate methods to be called or manually cause them to be called?
So from what I found, it doesn't call the method because the orientation hasn't changed.
What you have to do is to pass the button from the presenting view controller since it's already tied to the popover like this:
if(self.navigationItem.leftBarButtonItem != nil) {
newViewController.navigationItem.leftBarButtonItem = self.navigationItem.leftBarButtonItem;
}
// Push the newViewController

How to add a navigation bar to a UITableView

I added a subview to my application. The view controller is a UITableViewController. When I open the .xib file I see the table, but I can't drag a navigation bar onto it. So once the user enters the view, they have no way of getting back to the previous screen. What can be done?
the UITableView nib representation cannot have it. You can simulate the UI in the case you have a navigationController.
If you want to have a navigation controller, your UITableView has to be pushed into the stack of navigationController.
Assuming your view controller is ViewControllerA has a navigationController, then this method will make sure you have navigation controller in your UITableView:
[viewControllerA.navigationController pushViewController:tableViewController animated:YES];