I have code that uses Storyboards for seques, like so:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"ShowDiagnosis"])
{
[segue.destinationViewController setHappiness:self.diagnosis];
}
...
But I want to do it programmatically. I have myViewController class and when I click on a button I want to animate and push to myUINavigationController.
How is this done programmatically?
First things first, a segue cannot be created programmatically. It is created by the storyboard runtime when it is time to perform. However you may trigger a segue, which is already defined in the interface builder, by calling performSegueWithIdentifier:.
Other than this, you can provide transitions between view controllers without segue objects, for sure. In the corresponding action method, create your view controller instance, either by allocating programmatically or instantiating from storyboard with its identifier. Then, push it to your navigation controller.
- (void)buttonClicked:(UIButton *)sender
{
MyViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"my-vc-identifier"];
// OR MyViewController *vc = [[MyViewController alloc] init];
// any setup code for *vc
[self.navigationController pushViewController:vc animated:YES];
}
First of all segue can be used only with if you have a UINavigationController that will handle the navigation (push, pop, etc).
So if you have a UINavigationController and you want to push another UIViewController on the stack without using segue then you can use pushViewController:animated: method which also has a reverse popViewControllerAnimated:. Also UINavigationController provides other methods for adding/removing UIVIewControllers, for more info check UINavigationController class reference.
Related
I'm trying to move from one UIViewController to another using -pushViewController:animated using the below snipped :
SomeController *tabBar = [self.storyboard instantiateViewControllerWithIdentifier:#"mycus"];
[self.navigationController pushViewController:tabBar animated:YES];
Moving from one UIViewController (which has no UIViews or images) has a 3 second delay before moving. What is causing this issue and how would I solve it?
For storyboard, click on the segue you have created, give it an identifier like "someSegue".
Next you will want to trigger the prepareForSegue delegate in your viewcontroller doing the following...
[self performSegueWithIdentifier:#"SomeSegue" sender:nil];
..Then you will want to include the delegate method in your view controller and do any preparing you might want before the next view controller is initialised.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
SomeController *vc = [segue destinationViewController];
// Here you will want to do your prep e.g. pass iVars etc from one controller to the other.
}
I'm trying to use a custom segue (at bottom) to present a view controller modally with a blur view. I need to instantiate the view controller with properties before I present the view controller.
Instating the VC works great when I am using pushVC, but when I use perform segue with identifier, I don't see an option to choose an already instantiated VC.
CustomViewController* VC = [self.navigationController.storyboard instantiateViewControllerWithIdentifier:#"customVC"];
[self.navigationController performSegueWithIdentifier:#"blurSegue" sender:self];
How can I perform the custom segue and force it to use the view controller I allocated (called VC above)?
https://github.com/AlvaroFranco/AFBlurSegue
I need to instantiate the view controller with properties before I
present the view controller.
Why do you have to instantiate CustomViewController before triggering the segue. That shouldn't be necessary, if you need access to a property of CustomViewController before it's shown, you can set it in prepareForSegue.
Try this:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"blurSegue"]) {
CustomViewController *customViewController = (CustomViewController *)segue.destinationViewController;
customViewController.propertyToSet = XXX; // set the property here
}
}
Ah, by the way, instead of
[self.navigationController performSegueWithIdentifier:#"blurSegue" sender:self];
just use:
[self performSegueWithIdentifier:#"blurSegue" sender:self];
I have 3 different buttons which upon touch present the same UINavigationViewController with a container.
However, each button represents which view controller will be embed at the container.
How can I embed the necessary viewController by code?
what you can do is use an identifier which would be assigned to your various viewController as storyboardID
such as fisrtVC, SecondVC, thirdVC
the depending upon whichButton is pressed just set the identifier and use this identifier when
you want to push the controller such as
for example
while you push the navigation viewController just pass the storyboard Identifier such as
Declare a NSString *identifier;
-(IBAction)firstButtonClicked{
identifier=#"firstVC";
//pass this identifier to your navigationController
}
similarly for other Controllers
When you push the navigation controller make sure to pass this identifier along now depending upon the value you can initiate the controller on you VC as
on ViewDIdApppear:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
NSString* viewType = passedIdentifier
UIViewCOntroller* viewController = [storyboard instantiateViewControllerWithIdentifier:viewType];
Load this "viewCOntroller in your ContainerView"
You should implement prepareForSegue method:
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
id is your button that will fire segue. You do segues by drugging and drop in storyboard. Put an if statement in this method and tell your UIViewController which UIView to load in container. You can pass data like this:
// Get reference to the destination view controller
YourViewController *vc = [segue destinationViewController];
// Pass any objects to the view controller here, like...
[vc setMyObjectHere:object];
Second snippet taken from this answer.
Update.
To load different UIView in container put if statement into viewWillApper method.
This method firing earlier than viewDidLoad. If statement must check some property that tell what UIView to init. You setting up this property in prepareForSegue.
It will look like this:
if (self.viewToLoad == 1)
{
self.dynamicView = MyCustonUIViewNumberOne *view = [MyCustonUIViewNumberOne alloc] init];
}
Update 2.
Or you can do it dynamically like in this answer:
if (self.viewToLoad == 1)
{
// Replacing with your dimensions
CGRect frame = CGRectMake(x, y, width, height);
MyCustonUIViewNumberOne *dynamicView = [[MyCustonUIViewNumberOne alloc] initWithFrame:frame];
[self.container addSubview: dynamicView];
} else {
// Init other view
}
The container property:
I'm working with the Master-Detail project template that comes with Xcode and referenced in http://developer.apple.com/library/ios/#documentation/iPhone/Conceptual/SecondiOSAppTutorial/
Problem: I am trying to figure out how to add additional UIViewControllers to the default UINavigationController that this template comes with.
Specifically, I would like to add a DetailEditViewController after DetailViewController. Here is what I've done to this effect so far:
In DetailViewController I added an edit button to the navigationItem:
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationItem.rightBarButtonItem =
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit
target:self
action:#selector(editDetailItem:)];
[self configureView];
}
You can see it specifies a message selector editDetailItem:, which I've implemented as:
- (void)editDetailItem:(id)sender
{
[self.navigationController pushViewController:
[[DetailEditViewController alloc] init] animated:YES];
}
I've created a DetailEditViewController on the Storyboard, and the code runs without crashing, producing a black, blank window with a navigation item to take me back to detail. From here on I am pretty confused:
When I drag a new View Controller to the Storyboard, no corresponding code files are created! Am I responsible for making code files for these controllers? I see that Storyboard View Controllers are associated with a Class in the Identity Inspector... but why on earth would it not create templates for a new UIViewController when I drag one onto the Storyboard?
Should I be using a seque instead of -pushViewController to get from DetailViewController to DetailEditViewController? If so, I'm not sure how to add one on the Storyboard, because the navigationItem's UIBarButtonItems are all added in-code. There's nothing to Ctrl-drag from.
How do I send information from DetailViewController to DetailEditViewController? When MasterViewController segues to DetailViewController, it specifies the sender via - prepareForSegue:sender:
You're right, no corresponding files are produced. How is the system supposed to know what class you want? You need to create a UIViewController subclass, and change the class of the controller you drag in, to that class. The easiest way to push the new controller is to use a push segue -- if you don't have a UI element in the storyboard to connect that to, you connect it directly from the controller and give the segue an identifier (which I call "GoToEdit" in my example). In the action method for the edit button, then perform the segue:
[self performSegueWithIdentifier:#"GoToEdit" sender:self];
If you want to pass information, then you implement prepareForSegue:, something like this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"GoToEdit"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSDate *object = _objects[indexPath.row];
[[segue destinationViewController] setDetailItem:object];
}
}
It's a good thing to check the segue identifier first. Then you can access your destinationViewController (you might have to cast it to your class, so the compiler will recognize any property of it you're trying to set), and pass what you want to it.
I was wondering how to properly use the storyboard to put up a view controller modally. Personally I prefer working with xibs, but it seems that the storyboard is gaining popularity and will be the way to go in the future.
The way I would normally put up a view controller modally would be like this: let's say we have ViewControllerA (A for short) and ViewControllerB (B for short).
I would then normally put a protocol in B.h specifying the delegate method when B wants to be dismissed and add the id<theProtocol> delegate field as an assign property. Assuming i'm busy in A and I want to present B modally, I would write:
B* b = [[B alloc] initWithNibName:#"B" bundle:nil];
b.delegate = self;
[self presentModalViewController:B animated:YES];
Using the storyboard, I know it's possible to put up a different view controller in a modal way by ctrl-dragging from a button to a viewcontroller and selecting modal as transition type. I'm just wondering though; where do I set the delegate of the new view controller? What's the correct practice of passing things to your modal view controller? I don't really know what the whole deal with Segues is...
Take a look at this tutorial
According to it, you should set the delegate as follows:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"AddPlayer"])
{
UINavigationController *navigationController =
segue.destinationViewController;
PlayerDetailsViewController
*playerDetailsViewController =
[[navigationController viewControllers]
objectAtIndex:0];
playerDetailsViewController.delegate = self;
}
}
Where #"AddPlayer" is the name of your 'modal' segue
Instead of using the navigation controller you could directly use the UIStoryboardSegue object passed in prepareForSegue. It has a property called destinationViewController which is the view controller that is being instantiated. I find that a lot cleaner.
This is an example.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"AddPlayer"])
{
PlayerDetailsViewController
*playerDetailsViewController =
(PlayerDetailsViewController *) segue.destinationViewController;
playerDetailsViewController.delegate = self;
}
}
IMO I think that storyboards are great because they function like a blueprint of your application. Also I've never liked nibs. =D