Pushing a UIViewController from a UIView - iphone

I need to push a UIView into my UINavigation controller. I am doing it by
[self.view addSubview:showContactFlow];
And on a button click in UIView I need to push another UIViewController over the UIView. From the UIView I am not able to access self.navigationcontroller How can I do this?
Edit:
I have set the UIView as the view of a new UIViewController I am pushing into, the before mentioned UIViewController . Now I would like to know, how to handle the UIView button event inside its UIViewController, in which's view it is set.

Add a UINavigationController ivar to the UIView and assign it to the main view controller's. Then you should be able to access it from the UIView.
Edit:
Your UIView subclass:
// CustomView.h
#interface CustomView: UIView {
// ...
// your variables
// ...
UINavigationController *navController;
}
#property (nonatomic, assign) UINavigationController *navController; // assign, because this class is not the owner of the controller
// custom methods
#end
// CustomView.m
#implementation Customview
// synthesize other properties
#synthesize navController;
// implementation of custom methods
// don't release the navigation controller in the dealloc method, your class doesn't own it
#end
Then before the [self.view addSubview:showContactFlow]; line just add [showContactFlow setNavController:[self navigationController]]; and then you should be able to access your hierarchy's navigation controller from your UIView and use it to push other UIViewControllers.

You should try to work with an MVC approach. So your controller has access to all that stuff and can keep pushing and popping views, so the view doesn't need to know too much about the controller.
Otherwise, and for this case you can solve it fast by using delegation. So:
showContactFlow.delegate = self;
[self.view addSubview:showContactFlow];
So later in the UIView, you can just say:
[self.delegate addSubview:self];
This is gonna work, but it's not likely to be the best approach you should use.

On button click, you can present a view controller like,
-(void)buttonFunction{
ThirdVC *third= [[ThirdVC alloc]initWithNibNme];......
[self presentViewController:third animated:NO];
}
Using Core animation you can make NavigationController's pushviewController like animation on writing code in ThirdVC's viewWillAppear: method.

where do you add the UIButton is it in showContactFlow view or in the ViewController's view??
In regard to the modalViewControllers issue the correct method is
[self presentModalViewController:viewController animated:YES];
the standard animation in upwards

Related

presentModalViewController from app delegate

How can I present a modal view controller from the app delegate's view, the top most? Trying to present a modal view controller from a UIView, which made me confused.
Use your rootViewController. You can present a modal view controller from any view controller subclass. If your root VC is a UITabBarController, then you can do:
[self.tabBarController presentModalViewControllerAnimated:YES]
or if its a navigation controller:
[self.navigationController presentModalViewControllerAnimated:YES]
etc.
EDIT: MVC
By trying to present a controller from within a view you are breaking the MVC pattern. Generally, a view is concerned with its appearance and exposing interfaces to communicate user interface state to its controller. For example, if you have a UIButton in your view and you want it to present a modal view controller, you don't hard wire the view to do this. Instead, when a controller instantiates the view, the controller configures the button by setting itself as a target to receive the touchUpInside action where it can present the appropriate modal view controller.
The view itself does not (and should not) have this contextual knowledge to do the work of a controller.
The best way to do this is to create a new UIWindow, set it's windowLevel property, and present your UIViewController in that window.
This is how UIAlertViews work.
Interface
#interface MyAppDelegate : NSObject <UIApplicationDelegate>
#property (nonatomic, strong) UIWindow * alertWindow;
...
- (void)presentCustomAlert;
#end
Implementation:
#implementation MyAppDelegate
#synthesize alertWindow = _alertWindow;
...
- (void)presentCustomAlert
{
if (self.alertWindow == nil)
{
CGRect screenBounds = [[UIScreen mainScreen] bounds];
UIWindow * alertWindow = [[UIWindow alloc] initWithFrame:screenBounds];
alertWindow.windowLevel = UIWindowLevelAlert;
}
SomeViewController * myAlert = [[SomeViewController alloc] init];
alertWindow.rootViewController = myAlert;
[alertWindow makeKeyAndVisible];
}
#end
Application delegates do not manage a view. You should present a modal view controller from the -viewDidAppear: method of the first view controller that gets put on screen in -application:didFinishLaunchingWithOptions:.

UIViewController auto rotate not working

I have found quite a lot on this subject but I just can't figure it out. Any help would be massively appreciated!
I have an app set up with a UITabBarController. Within one of the tabs, I am showing a UITableView which is using a UINavigationController to allow for hierarchy. All the tables rotate just fine when the orientation is changed, until I get to what is effectively the final view in the hierarchy.
The final view is not a UITableView, just a basic UIView. But I can not get this page to rotate successfully! I have remade the view from with the absolute basics required and it still doesn't want to work! The code is below but it is currently pretty much a standard template with nothing in it now.
Also, I am not using InterfaceBuilder, and shouldAutorotateToInterfaceOrientation is on all views. This is the only one I am having problems with.
SomeView.h
#import <UIKit/UIKit.h>
#interface SomeView : UIViewController
{
NSString *someID;
NSString *someName;
}
#property(nonatomic,retain) NSString *someID;
#property(nonatomic,retain) NSString *someName;
#end
SomeView.m
#import "SomeView.h"
#import "AppDelegate.h"
#implementation SomeView
#synthesize someID, someName;
-(void)loadView
{
}
-(void)viewDidLoad
{
[super viewDidLoad];
}
-(void)viewDidUnload
{
[super viewDidUnload];
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return YES;
}
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
{
NSLog(#"willAnimateRotationToInterfaceOrientation");
}
-(void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
-(void)dealloc
{
[super dealloc];
}
#end
UPDATE 10th Nov 2011
I'm still having this issue, however looking through documents and bits this seems to be my problem (http://developer.apple.com/library/ios/#qa/qa1688/_index.html)
The view controller's UIView property is embedded inside UIWindow but alongside an additional view controller.
You may find a situation where shouldAutorotateToInterfaceOrientation is called once at startup for a given view controller but is never called again when the device is rotated. Because view controllers are tightly bound to the views they manage, they are also part of the responder chain used to handle events. View controllers are themselves descendants of the UIResponder class and are inserted into the responder chain between the managed view and its superview. So it is common practice to have one primary view controller in your application as part of the responder chain. You would typically add one primary view controller such as a UINavigationController, UITabBarController or a generic UIViewController to your UIWindow. For example, this is done by calling:
[myWindow addSubview:primaryViewController.view];
If you add an additional view controller's UIView property to UIWindow (at the same level as your primary view controller) via the following:
[myWindow addSubview:anotherController.view];
this additional view controller will not receive rotation events and will never rotate. Only the first view controller added to UIWindow will rotate.
My UITabBarController stopped to autorotate, when I added a new navigationController to it with a tableViewController and didn't notice, that my custom navigation controller's shouldAutorotateToInterfaceOrientation returns YES only for one orientation. The solution is to check shouldAutorotateToInterfaceOrientation function in each Controller inside TabBarController.
May be it will help to somebody.
And I have figured it out...
I was looking at the code which pushes the UIViewController onto the stack and I had not fully initied the UIViewController.

iOS4 - custom uiview accessing UINavigation stack

Bit confused with this one so bear with me...
I have a Navigation-based project which is working fine. I'm trying to create my first custom UIView to make a couple of buttons which I will use in multiple places. One of the buttons needs to push a viewcontroller into the navigation when it's clicked but I'm not sure how to do this.
When I had the button set up within a view controller I was using:
LocationViewController *controller = [[LocationViewController alloc] initWithNibName:#"LocationViewController" bundle:nil];
[self.navigationController pushViewController:controller animated:YES];
[controller release];
but the self.navigation controller won't work now, will it? How do I access the navigation controller of the viewcontroller that this uiview will be added to?
Hope at least some of that makes sense, as I said it's my first go at subclassing the uiview and adding it to multiple pages so I'm a bit lost.
EDIT TO ADD - I have the button click events inside the custom UIView, so that is where I'm trying to change the viewcontroller from. Should I instead wire up the events in whichever viewcontroller I add the view to?
Usually your appDelegate has a UINavigationController property. You can access it in your custom view like this:
UINavigationController *navController = (MyAppDelegate *)[[[UIApplication sharedApplication]
delegate] navigationController];
But more effective way is to make delegate method for your custom view and handle button action in your viewController.
MyCustomView.h
#protocol MyCustomViewDelegate
#interface MyCustomView : UIView {
id<MyCustomViewDelegate> cvDelegate; }
#property(nonatomic, assign) id<MyCustomViewDelegate> cvDelegate;
#protocol MyCustomViewDelegate #optional
-(void)didClickInCustomView:(MyCustomViewDelegate*)view withData:(NSObject*)data;
#end
MyCustomView.m
- (void)myButtonClick:(id)sender
{
[self.cvDelegate didClickInCustomView:self withData:someData];
}
So now you can handle this event in any place where is your custom
view.
Add the button from the interface builder or from the view controller's viewDidLoad using code:
CGRect frame = CGRectMake(0, 0, 24, 24);
UIButton *button = [[UIButton alloc] initWithFrame:frame];
[button addTarget:self action:#selector(handleMyButton:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
Then implement -(void)handleMyButton:(id)sender {}; in your view controller. Or you could instead write -(IBAction)handleMyButton:(id)sender {}; and link method and button using the interface builder.
Then inside the method just paste the block of code you posted above. If you started with the Xcode navigation controller template project it should work.
I think it's cleaner to hide the designated initializer initWithNibName: because it is an implementation detail.
When you say you are subclassing the UIView I don't know exactly what you mean. If you want to add another view controller with a custom view just use the UIViewController template and customize the XIB file, no need to subclass an UIView unless you are really modifying its behaviour, which I guess you are not. The view is a view, and the controller stuff like handling buttons should be in the controller.
The actual controller need to be in the navigation controller stack to be able to push another controller.
Or you can make a new navigation controller instance and push your LocationViewController.

Change views in a UIViewController

I have an UIViewController with a UIToolBar at the top with 3 buttons and a UIView, when touch upInside those buttons I have to change the views that the controller has. What can I do to get my porpuse? Thanks in advance.
You probably want to use something like a UINavigationController to control the view stack and then have your button(s) call one of these methods for the Touch Up Inside action:
pushViewController:animated:
popViewControllerAnimated:
popToRootViewControllerAnimated:
popToViewController:animated:
Here is a good uinavigationcontroller-tutorial to look into.
You need to do something like this for each of the actions you set up.
In the .h file of the current viewController:
#import "OtherViewController.h"
#interface MyViewController : UIViewController
{
OtherViewController *otherViewController;
}
#property(nonatomic, retain)IBOutlet OtherViewController *otherViewController;
Then in the .m file of the current viewController you need to add the following for each IBAction (touch up inside).
At the top of the .m file add:
#synthesize otherViewController;
Then make an IBAction and put the following line of code to display the other view:
[self presentModalViewController:otherViewController animated:NO];
In your otherViewController you can dismiss itself by using:
[self dismissModalViewControllerAnimated:NO];
NOTE: The other thing you will need to do is create a UIViewController in Interface Builder for each of the views you plan to display. You need to then go into the identity inspector and set the Class as OtherViewController. You then need to link the IBOutlet to the OtherViewController as normal.
There is a YouTube video tutorial which covers all of what I have mentioned above. It's a nice simple way to get started.
UiViewController view property is the base view you are seeing. It could be set(replaced with another). SO replace the view object of ViewController with another view you created.
UIView * customView = [[[UIView alloc] initWIthFrame:viewFrame] autorelease];
[self setView:customView];
Here self represent the current viewController.

How to get parent navigation controller in UIView

I have created a UITabBarController in my app delegate.
where each tab bar item holds a different UINavigationController that loads a custom UIViewController with a NIB (using -pushViewController:).
Inside one of the navigation controller, I load a custom UIView class with a custom NIB also.
This view is loaded multiple times inside the UIViewController.
The custom UIView has a UIButton, that on the event of touching it, I want to push a new UIViewController on the stack.
Problem is that I 'lost' the UINavigationController that holds the UIViewController.
I know I should use delegates, but haven't figured out who should which class should be the delegate.
Thanks in advance!
Neither .navigationController or .tabBarController will be available for a UIView or UIViewController that's been created but not pushed onto a stack
Either create a property on your View (or ViewController) class that is a UIViewController that is provided optionally after initialization or you could add a third argument to initWithNibName:bundle:
#interface CustomViewController : UIViewController
{
UIViewController *owner;
}
#property (nonatomic, assign) UIViewController* owner;
#end
Then in the owner ViewController:
CustomViewController *cvc = [[CustomViewController alloc] initWithNibNamed:nil bundle:nil];
cvc.owner = self;
It's too bad .parentViewController is read-only, this would be the sensible place for this.
You can get this using UIApplication class. Using this class you can find which viewController is placed at first. Here is the solution link for your problem.