How to anchor NSViewController as a popover? - objective-c

I have created a sample application with the following screen setup
Clicking on the load popover button simply calls the following code:
#IBAction func clicked(sender: AnyObject) {
self.performSegueWithIdentifier("test", sender:self)
}
As you can see in the segue properties, all that segue does is loads the viewcontroller with the anchor view being the button testAnchor3
The problem is: I dont know why the view is not anchoring. When ever i click on the LoadPopover button, the other view controller does load as a popover, but it anchors in the middle of the screen and not under the button like its supposed to. How do i get the popover to anchor correctly?

Create a outlet for your button and put it in presentViewController: toView as a view.
- (void)presentViewController:(NSViewController *)viewController asPopoverRelativeToRect:(NSRect)positioningRect ofView:(NSView *)positioningView preferredEdge:(NSRectEdge)preferredEdge behavior:(NSPopoverBehavior)behavior
{
//Change the ofView to be your button outlet
[super presentViewController:viewController asPopoverRelativeToRect:positioningRect ofView:popOverButton preferredEdge:preferredEdge behavior:behavior];
}

Related

Storyboard - Popping to a View Controller then Pushing Causes multiple pushes

In Objective C / iOS;
We have a process similar to this (set up in xcode storyboard);
Menu View Controller -> Enter in a code -> Process/Validate -> Present a Failed Code page
The (->) arrows signify a push segue setup in storyboard
When in failed state I want to pop to the Enter in a code view controller.
UIViewController *vc = nil;
NSUInteger index=0;
for (UIViewController *viewController in self.navigationController.viewControllers) {
if ([viewController isKindOfClass:[SomeViewController class]]) {
vc = viewController;
break;
}
index++;
}
if (vc) {
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self.navigationController popToViewController:vc animated:YES];
});
return;
}
This pops me back to the VC I want to go to.
Except now when I press a submit on the Enter code page it does 3 or 4 more "pushes", when it should only be 1.
Do I need to unwind the segue? I tried emptying the navigational view controller stack, and I even tried ridding it of its last active view controller -- both of these return a blank or black window view frame.
Why would popping a view controller in the navigation stack affect the segues in my view controller to the point where whenever I try to do a push segue action it will try to push multiple view controllers onto the stack?
Turns out I had the following issue
Button press causes segue action in storyboard
I did the same segue action in code on the button, hence pushing multiple times
I have now solved this issue

Some problems with segue and splash screen

I am trying to make a splash screen, but tutorial says, I should make a segue from StatusBar of the ViewController, where my Splash screen is, to the next one ViewController, that is a start page. This tutorial is obviously too old, because I have the last XCode.
How should it be done?
Go to the storyboard, insert a UINavigationController and connect it to the UIViewController you want to make your splash screen. If you haven't created any, you can use the UIVewController that will be inserted with the UINavigationController you drag into your storyboard. Now create new classes of type UIViewController and set them as Custom Class for the splash screen in the storyboard (inside the Identity inspector). Into the .m file you have to insert following code to perform a segue to another UIViewController:
- (void)viewDidLoad{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self performSelector:#selector(goToLandingPage)
withObject:nil
afterDelay:3.0f];
}
- (void)goToLandingPage{
[self performSegueWithIdentifier:#"landingpage" sender:self];
}
Next you have to create a second UIViewController inside thestoryboardand drag a segue from the splash to the nextUIViewController(don't forget to pressSTRG, and zoom out). Click on thissegueand insert the identifier (in theAttributes Inspector` on the right), in my case landingpage.
Everytime you want to perform a segue programmatically inside your code, you have to select the UIViewController it self inside the storyboard and drag it to the controller you want. Otherwise just use a UIButton and it will perform by click.

Hide MasterViewController when clicking a button

I have a Master/Detail application and everything works right..i added a button with the purpose of taking me to another tableViewController. I need, when i go to that table view controller, to hide permanently the master view controller from portrait and landscape mode.So to recapitulate, i am in a newly created table view controller independent from the original Detail View Controller, and i need to hide permanently the master view controller when this button is clicked and the new TableViewController is loaded..How can i do it ? I tried to use a MGSplitViewController but i got lost using it..i'm a newb in Xcode development. Any help will be highly appreciated.Update 1:My problem is not with the Detail View Controller...in the Detail ViewCOntroller i have added a button that will take me to another tableviewcontroller...now when i load that i need to force the masterviewcontroller to stay hidden how can i do it?
Once you configure your detail view controller, you need to need to dismiss the popover controller.
if (self.popoverController) {
[self.popoverController dismissPopoverAnimated:YES];
}
If your detail view controller doesn't already have a property to hold the UIPopoverController, you can capture it by implementing these delegate methods for UISplitViewControllerDelegate
- (void)splitViewController:(UISplitViewController *)iSplitViewController
willHideViewController:(UIViewController *)iViewController
withBarButtonItem:(UIBarButtonItem *)iBarButtonItem
forPopoverController:(UIPopoverController *)iPopoverController {
self.popoverController = iPopoverController;
}
- (void)splitViewController:(UISplitViewController *)iSplitViewController
willShowViewController:(UIViewController *)iViewController
invalidatingBarButtonItem:(UIBarButtonItem *)iBarButtonItem {
self.popoverController = nil;
}

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";
...
}

Modal UIViewController will not push to next UIViewController

The start of the structure is as follows...
UITabBarController -> UINavigationController(s)
From each of the UINavigationControllers, I have a UIBarButtonItem that modally presents a UIViewController.
This UIViewController has a MKMapView with pins at multiple locations. When clicked, they display an annotation with a disclosure button.
Within this UIViewController, it is my intention to push a detail page (UITableViewController) when pressing the disclosure button of the annotation. The method calloutAccessoryControlTapped: receives the appropriate pin, but the transition to the next controller fails.
I have tried every combination of the following methods...
[self.navigationController ...]
[self.parentViewController ...]
[self.parentViewController.navigationController ...]
with the method being either...
presentModalViewController:
pushViewController:
I have done all of these with the UIViewController being on its own, and also with it embedded inside of a UINavigationController.
All of these properties return null...
self.navigationController
self.parentViewController
self.parentViewController.navigationController
This is the first time I've used storyboard for an Xcode project. Am I missing a step?
Try getting rid of the code and implementing the transitions in storyboard by control dragging from the button to the view controller you wish to load modally. When the "Storyboard Segue" menu pops up select "modal". In the modal view controller, I like to use code to return from the modal by calling:
[self dismissModalViewControllerAnimated:YES];
To Presenting Storyboard View Controllers Programmatically scroll to that section in gravityjack on the link provided.
For example, I have a view controller that I created in storyboard which I can call programmatically with the following two statements:
SettingsViewController *settingsVC = [self.storyboard instantiateViewControllerWithIdentifier:#"settingsVC"];
[self.navigationController pushViewController:settingsVC animated:YES];