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
}
}
Related
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"];
}
I have a View-based app. The first view that is loaded has a button which loads another view using this code:
AddPost *addView = [[AddPost alloc] initWithNibName:#"AddPost" bundle:nil];
addView.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:addView animated:YES];
What I want to do is provide a button on the view (AddPost) that will let me close it and go back to the original view. How can I do this?
It seems a little strange, but you can actually have addView call:
[self dismissModalViewControllerAnimated:YES];
From the docs:
"The parent view controller is responsible for dismissing the modal view controller it presented using the presentModalViewController:animated: method. If you call this method on the modal view controller itself, however, the modal view controller automatically forwards the message to its parent view controller."
The answer Conrad gave will work perfectly well. In the name of slightly better encapsulation you could put a delegate protocol on addView and have your first view implement this.
So in the header file for your addView controller:
#protocol addViewDelegate <NSObject>
- (void)addViewRequestDismissal;
#end
You will also need an external properly on the addView controller:
#property (assign) id<addViewDelegate> delegate;
Then make your first view controller implement this, so in it's .h file you should have
#interface firstView : NSObject <addViewDelegate> {
}
When you instantiate your addView remember to set the delegate:
addView.delegate = self;
In the addView controller when your button is pressed call back:
- (void)buttonPressed {
[self.delegate addViewRequestDismissal];
}
Finally in your first view remember to implement this method
- (void)addViewRequestDismissal {
[self dismissModalViewControllerAnimated:YES];
}
Hope all goes well with this. Post back if you have any further problems :)
I have a UIViewController within a UINavigationController, and I'm pushing a second UIViewController onto the navigation stack from a XIB file. This XIB also includes a UINavigationItem for the second view controller's title and button, but these are ignored when loading the XIB. Any ideas?
Here is my code (photoViewController is the second viewController)
- (void) displayPhotoWithId:(int)photoId {
if (_photoViewController == nil) {
self.photoViewController = [[[PhotoViewController alloc] initWithNibName:#"PhotoView" bundle:[NSBundle mainBundle]] autorelease];
}
_photoViewController.photoId = photoId;
[self.navigationController pushViewController:_photoViewController animated:YES];
}
You can wire this up from interface builder. Add something like this to your view controller:
IBOutlet UINavigationItem* navigationItem;
Then wire it up to the view controller outlets (from File Owner, presumably, to the UINavigationItem in your XIB). I have done this and it works fine. I suppose UINavigationController looks for the 'navigationItem' automagically.
Navigation item is ignored because it has nothing to do with this controller, it's just happened to be in this controller's XIB. Controller's navigation item is created on instantiation. You have to setup title and navigation buttons in code (in viewDidLoad for example) because controller doesn't have navigationItem outlet. UINavigationItem in XIB works only inside UINavigationController's root controller.
I'm trying to essentially re-implement the UISplitViewController (because it has its limits), but when I create a UIViewController viewController, and then do an "[viewController.view addSubview contentViewController.view]" on it, to add a view that already has a view controller, that content view doesn't seem to get initialised by its view controller. I guess its view controller is getting detached or deallocated, is this the case?
Can you post your code?
UIViewController* myController = [[UIViewController alloc] initWithNibName:#"myView" bundle:nil];
myViewClass* cellView = (myViewClass*)cellController.view;
[self addSubview:cellView];
The above code will add a subview using the view in the "myView" nib.
Ensure that in the nib file -
The view is of myViewClass
the File's Owner is UIViewController and
its view outlet is connected to the view.
In my app I have a drill-down type interface as follows:
My root view, which has a list of items and an "Add" button.
Selecting an item pushes the "Detail" view on the navigationController.
Selecting the "Add" button pushes an "Add" view.
How would I transition between the Add view to the Detail view?
I'm thinking of doing an unanimated "pop" on the Add view and push the Detail controller on, but how do I make the second part animated, so the detail view would either slide in vertically or fade in from the Add view?
Thanks,
Kelso
Based on Ramin's reply, you can try this way, which is used by Apple in several samples:
MyListViewController.h
#import "MyAddViewController.h"
#interface MyListViewController : UITableViewController <MyAddViewControllerDelegate> {
}
- (IBAction)add:(id)sender;
#end
MyListViewController.m
// Action for bring up add view controller
- (IBAction)add:(id)sender {
MyAddViewController *addViewController = [[MyAddViewController alloc] initWithStyle:UITableViewStyleGrouped];
addViewController.delegate = self;
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:addViewController];
[self presentModalViewController:navigationController animated:YES];
[navigationController release];
[addViewController release];
}
// MyAddViewController's delegate method, dismiss the add view controller in here
- (void)addViewController:(MyAddViewController *)addViewController didAddData:(MyData *)data{
if (data) {
MyDetailViewController *detailViewController = [[MyDetailViewController alloc] initWithStyle:UITableViewStylePlain];
detailViewController.data = data;
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
}
[self dismissModalViewControllerAnimated:YES];
}
MyAddViewController.h
#protocol MyAddViewControllerDelegate;
#class MyData;
#interface MCCourseAddTableViewController : UITableViewController {
#private
MyData *data;
id <MCCourseAddDelegate> delegate;
}
// MyData could be NSManagedObject if you want to use Core Data
#property(nonatomic, retain) MyData *data;
#property(nonatomic, assign) id <MyAddViewControllerDelegate> delegate;
- (void)save;
- (void)cancel;
#end
#protocol MyAddViewControllerDelegate <NSObject>
#optional
- (void)addViewController:(MyAddViewController *)addViewController didAddData:(MyData *)data;;
#end
MyAddViewController.m
- (void)save {
if (self.delegate != nil) {
if ([self.delegate conformsToProtocol:#protocol(MyAddViewControllerDelegate)]){
if ([self.delegate respondsToSelector:#selector(addViewController:didAddData:)]){
// Send data back to List View, to bring up detail view controller and dismiss add view controller
[self.delegate addViewController:self didAddData:self.data];
}
}
}
}
- (void)cancel {
if (self.delegate != nil) {
if ([self.delegate conformsToProtocol:#protocol(MyAddViewControllerDelegate)]){
if ([self.delegate respondsToSelector:#selector(addViewController:didAddData:)]){
// Send nil back to ListView, to dismiss the add view controller only
[self.delegate addViewController:self didAddData:nil];
}
}
}
}
You could push the Add View onto the Details view and set a variable to remember that.
When the user try to pop the Add View, you check the previous variable and, if set, you pop directly to the root controller(that should pop the Details view automatically).
Marco
Make the add view a modal and in there provide a "Done" (or "Save") and a "Cancel" button. If the user hits cancel, you just close the modal. If they hit Done you save the new record to the table model, then do a table reload on the root view before returning. To be nice, you can flash the newly added item.
A clean way to set this up is to make the modal controller implement a delegate that expects a 'Done' protocol method and have the root controller implement it and set itself as the delegate.
This way, the root controller is notified when the user hits 'Done' so it can encapsulate all that needs to happen. If you want to go directly from add to detail view the delegate method can do a 'push' for the newly added record and you'll get a nice transition from modal sliding down to detail view.