I have a function that returns a view to be displayed. When I use:
UIViewController* vcontroller= [storyboard instantiateViewControllerWithIdentifier:#"meterEnlarge"];
return vcontroller.view;
I see the view. However, when I do:
ViewController_Meter_Enlarge_iPad* controller = [[ViewController_Meter_Enlarge_iPad alloc]init];
return controller.view;
I don't see the view. Considering I need to modify properties on the VC the second option is critical to me (as I start calling [controller setxyz], etc). How can I return the view from the VC?
The view won't be set unless you create the view controller and initialize it from a NIB file:
- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle
(reference)
(or manually assign a view to the view controller).
I take it that you expect the first view controller (the one from the storyboard) to be of your custom view controller class? In that case, you can check the actual class of the view controller returned to you from the storyboard, and do your custom setup if it matches the class that you want:
UIViewController *storyboardVC =
[storyboard instantiateViewControllerWithIdentifier:#"meterEnlarge"];
if ([storyboardVC isKindOfClass:[ViewController_Meter_Enlarge_iPad class]]) {
ViewController_Meter_Enlarge_iPad *customVC =
(ViewController_Meter_Enlarge_iPad *)storyboardVC;
[customVC setXYZ:#"foo"];
}
Related
I am presenting a view controller from another view controller using presentViewController.
The presenting view controller (The "SourceViewController") creates the new view controller and assigns it to a navigation controller before presentation (because the "NextViewController" wants a navigation bar and navigation controller).
// from the source view controller
#implementation SourceViewController
-(void)showNextViewController
{
NextViewController *viewController = [[NextViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController];
[self presentViewController:viewController animated:YES];
}
#end
#implementation NextViewController
// in NextViewController
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationPortrait;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
#end
But when I present the view controller when the originating view controller is in landscape the "NextViewController" isn't presented in portrait but rather in landscape like the source view controller.
I've tried many combinations of rotation methods but haven't been able to get it to present in the correct orientation.
I assume that it is possible because many apple components like UIImagePickerController are always presented in portrait , so how do I force its orientation?
Thanks
EDIT:
I've created a UINavigationController sub class:
PortraitNavigationController : UINavigationController
#implementation
-(BOOL)shouldAutorotate
{
return NO;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
#end
and then when presenting the NextViewController
PortraitNavigationController *nav = [PortraitNavigationController initWithRootViewController:nextViewController];
[self presentViewController:nav animated:YES];
and now NextViewController is indeed in portrait - but when I rotate the device to use this view controller and eventually dismiss it - the underlying source view controller looks all messed up.
The underlying view controller is a custom container view controller which is embedded in a UINavigationController
The containers it uses to display the child view controllers are not in their correct places
I don't want the container view controller to rotate at all as soon as the NextViewController is displayed and dismissed.
When you rotate your device the presented view controller is asked about the rotations and orientations it supports - In your case it's a UINavigationController and not an instance of NextViewController. One way to fix this is to subclass UINavigationController and override the rotation methods and forward the calls onto it's root view.
As a side not UIImagePickerController is a subclass of UINavigationController. It might make more sense to make NexViewController a subclass of UINavigationController and then inside that subclass initialize it with the correct root view controller.
Another option is to just alloc and init a UINavigationBar inside of NextViewController and add it as a subview if you don't need to use the navigation controller for anything. In this case autolayout comes in handy because you can pin it to the top, left, and right and let it figure out the correct size and location for it.
I have two view controller classes. On the first, I have an image view and on second view controller there is a text view. The second view controller has a done-button, on clicking done-button I want to add a label on the first view controller's image and pass text view's text on that label.
Is there any way to do it?
Please suggest me.
Use delegates. Create a protocol on the Second view controller
and make the First view controller its delegate. Use delegate methods to send the textview's text as message to the delegate (or in general, send any kind of data between classes).
Keep a reference to the second view controller in the first view controller.
Call a public function in the second view controller from the first view controller.
View Controller A:
#interface ViewControllerA : UIViewController
{
#public
NString *text;
}
View Controller B:
#interface ViewControllerB : UIViewController
{
#public
ViewControllerA *refToA;
}
Code to launch view controller B from A:
ViewControllerB *vc = [[ViewControllerB alloc] initWithNibName:#"ViewControllerB" bundle:nil];
vc->refToA = self;
[self presentModalViewController:vc animated:YES];
in View Controller B set the value:
refToA->text = #"text to pass";
[refToA.view addSubview:button];
View did appear in A:
- (void)viewDidAppear:(BOOL)animated
{
if (text != nil)
{
NSLog(#"%#", text);
// create your button here
}
}
I migrated a project from using XIB's to Storyboard, according to these instructions: https://stackoverflow.com/a/9708723/2604030
It went good.
But I can't make the segues work programmatically, and I need to use them this way, because I have 2 buttons that link to the same ViewController, with different types, hope you understand why from this image.
There are 2 difficulty mode buttons. The code I use:
`- (IBAction)btnNormalAct:(id)sender {
LevelController *wc = [[LevelController alloc] initWithNibName:#"LevelController" type:0];
[self.navigationController pushViewController:wc animated:YES];
}
- (IBAction)btnTimedAct:(id)sender {
LevelController *wc = [[LevelController alloc] initWithNibName:#"LevelController" type:1];
[self.navigationController pushViewController:wc animated:YES];
}`
This worked when I used XIB's, and I am sure I linked everything correctly in the storyboard's VCs. The seagues works if I make them from the storyboard. But how can I manage this situation.
ALSO: are those lines good when changing from XIB's to Storyboard? Is that the right way to do this change (the way shown in the link above)?
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
}
You can use the PrepareForSegue method to set things on the incoming view controller before it is called:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Make sure your segue name in storyboard is the same as this line
if ([[segue identifier] isEqualToString:#"YOUR_SEGUE_NAME_HERE"])
{
// Get reference to the destination view controller
LevelController *vc = [segue destinationViewController];
// Pass any objects to the view controller here, like...
[vc setType:1];
}
}
Don't use the button actions. Connect the segues to the buttons and give the segues unique identifiers. Then implement prepareForSegue:sender: in your controller. When the method fires, check the seque identifier and set the appropriate type on the `destinationViewController'.
When using a storyboard you should instantiate your controllers from the storyboard rather than using initWithNibName:bundle:. This is done by giving each view controller a unique identifier and then calling instantiateViewControllerWithIdentifier: (or, for the initial view controller, just instantiateInitialViewController) on the storyboard which you can get from the current controller (or if required with storyboardWithName:bundle:).
I am currently trying to copy an array I have to a new view that I am creating programmatically. I actually have found how to do this with normal navigation controller syntax. My issue is I'm using the new storyboard and I don't know the syntax to do the same thing. Here is the code I have..
CustomerListViewController *second = [[CustomerListViewController alloc] initWithNibName:#"CustomerListViewController" bundle: nil];
[second setValue:customerList.list];
// [self.navigationController pushViewController:second animated:YES];
[self performSegueWithIdentifier:#"LoginSegue" sender:self];
as you can see, I am programmatically creating the second view controller and storing the local array customerList.List to the created view controller's array variable. The next step is to open the new created view. The line commented out is the syntax to open the view under a navigation controller. The line below is the storyboard way, but minus specifying the view I created. I need to know the syntax for the storyboard to do the same thing as the navigation controller.
It does not make sense to create your own instance of CustomerListViewController here if you're using segues. The segue itself will create the view controller from the storyboard and the instance you have created here will do nothing.
Instead, just call performSegueWithIdentifier:sender: here. Then implement the prepareForSegue:sender: method like this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"LoginSegue"]) {
CustomerListViewController *destinationController = (CustomerListViewController *)segue.destinationViewController;
[destinationController setValue:customerList.list];
}
}
In my app I've added a label to a view, connected it to an outlet but nothing shows up when I first assign this outlet from another view controller and then call pushViewController to display it. Here's the code before pushing next view that display the label:
CustomViewController *vc = [[CustomViewController alloc] init];
vc.lbl_price.text = self.label_price.text; // lbl_price is defined as a property in CustomViewController and label_price is defined in current view controller
[self.navigationController pushViewController:vc];
In the CustomViewController viewDidLoad method I added this instruction to see if it should work
NSLog(#"Price=%#",lbl_price); // it actually prints out what was previously assigned
But it doesn't show into the label!
Any idea why ?
Stephane
Even if view controller is created its view hierarchy may not (and so all subviews will still be nil), for optimization reasons it may not be loaded until you try to actually access controller's view. You have two options to solve your problem:
Store all values in separate non-UI variables and assign them to UI components with controller is going to appear:
// Before push controller
vc.myPriceText = self.label_price.text;
// In controller's viewWillAppear:
self.lbl_price.text = self.myPriceText;
Make [vc view] call to force controller to load its view hierarchy:
CustomViewController *vc = [[CustomViewController alloc] init];
[vc view];
vc.lbl_price.text = self.label_price.text;
[self.navigationController pushViewController:vc];