I am very new to Obj-C and learning iphone development.
My question is how to add subview from app delegate.
Lets say I added subview called "MainView" from "applicationDidFinishLaunching" method.
- (void)applicationDidFinishLaunching:(UIApplication *)application {
MainViewController *aViewController = [[MainViewController alloc] initWithNibName:#"MainView" bundle:nil];
self.mainViewController = aViewController;
[aViewController release];
[window addSubview:mainViewController.view];
// Override point for customization after application launch
[window makeKeyAndVisible];
}
"MainView.xib" file has a button to show its child view. When the button is clicked, it calls "showChildView" method.
- (IBAction)showChildView:(id)sender {
if (self.childViewController == nil) {
ChildViewController *childController = [[ChildViewController alloc] initWithNibName:#"ChildView" bundle:nil];
self.childViewController = childController;
[childController release];
}
[self.view insertSubview:childViewController.view atIndex:0];
}
From this code, when app launches, it shows "MainView" with a button. But when I clicked the button, the button is still visible as well as the content from the "ChildView.xib" file too.
How can I hide the "MainView" when I pressed the button and show only the contents of the "ChildView"?
Thanks for your help in advance.
well, you have to remove the original view first, before inserting the new subview, do it this way
- (IBAction)showChildView:(id)sender {
if (self.childViewController == nil) {
ChildViewController *childController = [[ChildViewController alloc] initWithNibName:#"ChildView" bundle:nil];
self.childViewController = childController;
[childController release];
}
[self.mainViewControlle.view removeFromSuperView];
[self.view insertSubview:childViewController.view atIndex:0];
}
Hope this helps.
You might want to check out the Utility App sample -- it demonstrates switching between two views with animation and adding/removing views from parent views.
you might want to create a navigation controller in the main view and than push the childviewcontroller onto it when invoking showChildView. You'll get the back navigation button for free that way
Related
I have page-based app. On each page I have 3 uibuttons at the top, uiscrollview with alphabet (uibuttons to sort data in uitable) at the right and uitableview at the center. How to show cell's detail view? If it is necessary to add uinavigationcontroller I can't do this. If I adds it, it disables interaction with my table, buttons and scrollview.
And another question is how to show new data in tableview and scrollview when goes to next page??
I have rootViewController class and DataViewController class.
rootViewController listing:
#interface RootViewController ()
#property (readonly, strong, nonatomic) ModelController *modelController;
#end
#implementation RootViewController
#synthesize pageViewController = _pageViewController;
#synthesize modelController = _modelController;
#synthesize navContr = _navContr;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Configure the page view controller and add it as a child view controller.
//[self presentModalViewController:navContr animated:YES];
self.pageViewController = [[[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil] autorelease];
self.pageViewController.delegate = self;
DataViewController *startingViewController = [self.modelController viewControllerAtIndex:0 storyboard:self.storyboard];
NSArray *viewControllers = [NSArray arrayWithObject:startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:NULL];
self.pageViewController.dataSource = self.modelController;
[self addChildViewController:self.pageViewController];
[self.view addSubview:self.pageViewController.view];
self.navContr = [[UINavigationController alloc] initWithRootViewController:self.pageViewController];
[self.view addSubview:self.navContr.view];
// Set the page view controller's bounds using an inset rect so that self's view is visible around the edges of the pages.
CGRect pageViewRect = self.view.bounds;
self.pageViewController.view.frame = pageViewRect;
[self.pageViewController didMoveToParentViewController:self];
// Add the page view controller's gesture recognizers to the book view controller's view so that the gestures are started more easily.
self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;
for (UIGestureRecognizer *recognizer in self.pageViewController.gestureRecognizers){
if ([recognizer isKindOfClass:[UITapGestureRecognizer class]]){
[recognizer setEnabled:NO];
}
}
}
After few manipulations it works but I need help to get it work fine!
So now it looks like this
Next question: how do I remove the brown space at the top???
::UPDATE::
Problem solved. It needs just to set y-axis position of UINavigationController to -20 ;)
i'm not sure if this link about creating navigation-based project may help you.. (http://iosmadesimple.blogspot.com/2012/08/navigation-based-project-doing-it.html)
From that tutorial, there's a class called SampleViewController, subclass of UIViewController. You might want to put a tableView in SampleViewController.xib file. Then in your SampleViewController.h file, add an IBOutlet UITableView* yourTable property and synthesize it. Connect it to your tableView in your .xib file. //Or you may do it programmatically
in your SampleViewController.h, make your interface header look like this.. I think you already know this...
#interface SampleViewController:UIViewController < UITableviewDelegate, UITableViewDatasource >
in your SampleViewcontroller.m, under viewDidLoad method, set the table delegate and datasource to self:
yourTableView.delegate = self;
yourTableView.datasource = self;
Afterwhich, you implement tableView delegate and datasource methods... //you already know those since you were already able to show a tableview ;)
one of these methods is the "tableview:didSelectAtIndexpath:" --> this is the part wherein you can put your code when you click one of the cells.
Let's assume you have the DetailsViewController Class, this is the class you would like to show after clicking a cell and show its details.
DetailsViewController Class must have a variable that will accept the data you would like to show. Let's say, an NSString *detailsMessage; //do the #property and #synthesize thing...
Let's go back to SampleViewController.m file, under tableview:didSelectAtIndexpath: Method:
inside that Method.. put these codes.
DetailsViewController *detailsVC = [[DetailsViewController alloc] init];
detailsVC.detailsMessage = #"The Data you want to pass.";
[self.navigationController pushViewController:detailsVC animated:YES];
I hope this helps. :(
There may be other ways but by far the easiest way is to use a navigation controller. In fact, it is built to do exactly this.
If you don't want the navigationBar then you can hide it in the viewWillAppear function.
[self.navigationController setNavigationBarHidden:YES animated:YES];
Then you can add an other UIViewController to push when the user selects a cell.
Having read your OP again I'm not sure how you are adding your navigationController.
To use a navigationController you create it and load it at start time. You then create your current viewController (the one with the buttons and table etc...) and set this as the rootViewController of the navigationController.
Then you display the navigationController.
Could you explain how you are adding your navigationController as it may help understand what is going wrong.
Thanks
::EDIT::
OK, my assumption was correct.
The way you are using the navigation controller is not how it was intended.
OK, so at the moment your AppDelegate file will have a method Application didFinishLaunching...
It will look something like this...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[OJFViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
You should change it so that it is like this...
first add a property to your appDelegate...
#property (nonatomic, strong) UINavigationController *navigationController;
Then change the didFinishLaunchingMethod to this...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[OJFViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
return YES;
}
This will still show you MainViewController but it will now be contained within a navigationController.
Next in your MainViewController function viewWillAppearAnimated add the line...
[self.navigationController setNavigationBarHidden:YES animated:animated];
This will then hide the navigationBar at the top of the view so you still have access to your buttons.
The you need a new ViewController and xib file (for example DetailViewController).
When the user selects a table row you need to then do something like...
DetailViewController *detailView = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
//pass in details of which row was selected.
[self.navigationController pushViewController:detailView animated:YES];
This will then display your new view and new viewController. You will also need to write a way of passing the data in (set up a property on the DetailViewController).
Hope this helps.
I'm having trouble coding a button to go to the previous page. I was able to do it to go to the next page thinking if I did the same thing but changed it a bit it would work in reverse. Unfortunately, I come up with a lot of errors I can't resolve because it won't allow me to use the release function.
This is this the code that helps it to work going to the next page fine:
#import "ViewController.h"
#implementation ViewController
-(IBAction)btnClicked:(id) sender
{
//add the view of the view controller to the current View---
if (menuView==nil) {
menuView =
[[MenuView alloc] initWithNibName:#"MenuView"
bundle:nil];
}
[self.view addSubview:menuView.view];
}
-(void)dealloc {
[menuView release];
[super dealloc];
}
How do I do it so that a back button will go to the previous page though.
It's pretty simple, use this :
-(IBAction)back:(id) sender
{
[menuView.view removeFromSuperview];
}
But, I would suggest not using addSubview: for many views as it would be complex way to do. Use UINavigationController as #Paul.s suggested.
The way you are doing this is not quite correct and I would suggest doing some reading to get familiar with iOS programming.
Your program structure should be: create a navigation controller (2) to manage the stack of view controllers giving it a viewController (1) to act as it's root.
// AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// 1
FirstViewController *firstViewController = [[FirstViewController alloc] init];
// 2
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:firstViewController];
[firstViewController release]; firstViewController = nil;
self.window.rootViewController = navigationController;
[navigationController release]; navigationController = nil;
[self.window makeKeyAndVisible];
return YES;
}
This will display your first view controller inside a UINavigationController. A UINavigationController is responsible for managing a stack of UIViewController's and giving you UI to navigate back down the stack as well as calling all the appropriate presentation related methods on a UIViewController at the correct times e.g. viewDidLoad. You should check out The View Controller Programming Guide for lots of info
Then inside your first view controller you do something like this to respond to the button:
- (IBAction)buttonClicked:(id)sender;
{
SecondViewController *secondViewController = [[SecondViewController alloc] init];
[self.navigationController pushViewController:secondViewController animated:YES];
[secondViewController release]; secondViewController = nil;
}
This creates a new view controller and pushes it onto the stack.
When I push cancel button in the third view, I want to go back to the first view directly.
I also want to remove the second view.
How can I do that?
This is the code.
// this part is in the first view.
self.second = [SecondController alloc] init];
[self.view addSubview:second.view];
// this part is in the second view.
ThirdController *thirdController = [[ThirdController alloc] initWithStyle:UITableViewStyleGrouped];
self.navigationController = [UINavigationController alloc] initWithRootViewController:thirdController];
[self.view addSubview:navigationController.view];
// this part is in the third view.
- (void)cancel {
[self.view removeFromSuperview]; // this only goes to the second view.
}
EDIT:
Can I use popToViewController in called contoller? My app crashes.
I thought popToViewController can be used only in calling controller.
And popToViewController is used when it was pushed.
I did add not push.
[self.navigationController popToViewController:[[self.navigationController viewControllers] objectAtIndex:0] animated:YES];
popToViewController:animated: is a UINavigationController method that you use when popping view controllers off the navigation controller stack. It doesn't fit for this scenario.
This user is adding subviews, not pushing them on a navigation controller stack.
As a note, it appears as a matter of design you should be using a navigation controller with the first view as the root controller, then the second pushed on the stack, and the third pushed on the stack. Then all you have to do is [self.navigationController popToRootViewControllerAnimated:YES].
I think this will work if you want to keep your current architecture:
// this part is in the third view.
- (void)cancel {
// remove the second view (self.view.superview) from the first view
[self.view.superview removeFromSuperView];
// can't recall, possibly you still need to remove the third view, but i think removing the superview will do it.
// [self.view removeFromSuperView];
}
If you prefer to try the UINavigationController route, then the easiest path is to create a new project in Xcode and select the type for a Navigation-Based Application or a Master-Detail Application. This will create a UINavigationController in a nib and add it to your window. You can then set the root view controller in Interface Builder to your FirstViewController class.
If you prefer to create the UINavigationController in code, then that is also possible. I show that below, along with the rest of the code you need, regardless of whether you create your UINavigationController in a nib in IB or in code.
I also recommend reading the View Controller Programming Guide for iOS.
In your app delegate or some other code:
-(void)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions [
// I would recommend setting up the UINavigationController and FirstViewController as IBOutlets in your nib, but it can be done in code.
FirstViewController* fvc = [[FirstViewController alloc] initWithNibName:#"FirstView" bundle:nil];
UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:fvc];
[window addSubView:navController.view];
[window makeKeyAndVisible];
[fvc release];
[navController release];
}
In the first view controller:
SecondViewController* svc = [[SecondViewController alloc] initWithNibName:#"SecondView" bundle:nil];
[self.navigationController pushViewController:svc animated:YES];
[svc release];
In the second view controller:
ThirdViewController* tvc = [[ThirdViewController alloc] initWithNibName:#"ThirdView" bundle:nil];
[self.navigationController pushViewController:tvc animated:YES];
[tvc release];
In the third view controller:
-(void)cancel {
// returns to the first view controller
[self.navigationController popToRootViewControllerAnimated:YES];
}
Use
- (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated
to go back to a specific view controller.
Try this:
[self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:1] animated:YES];
This will pop to the view at index 1. Hope that Helps!
// this part is in the third view.
- (void)cancel {
self.first = [SecondController alloc] init];
[self.view addSubview:second.view];
}
And I think if you have you don't need to be worried about removing beneath view, later these will removed.
I'm wanting to have my app (on launch) load a view that I have created over the top of the original view, then when a button is clicked the top view will disappear and show the main view underneath. I know this is terribly simple, but how would I do this? Maybe push the view in viewDidLoad?
Use a navigation controller
MyViewController *myView = [[MyViewController alloc] init];
UINavigationController *navControl = [[UINavigationController alloc] initWithRootViewController:myView];
My2ndView *secondView = ....
[navControl pushViewController:secondView animated:NO];
[window addSubView:navControl.view]
This can be incredibly simple. When the user clicks the button, just do this
secondViewController.view.hidden = YES;
Just add the two views in your delegate, and do that in your delegate.
If you prefer, just do it "in" secondViewController! self.view.hidden = YES;
It sounds like you're just doing something simple ...... no need to bother with a view controller.
You ask how to display the second view, just like this ..
-(BOOL)application:(UIApplication *)applic`ation
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[window addSubview:yourMainView.view];
[window addSubview:theTemporaryView.view]; // it goes on top
[window makeKeyAndVisible];
application.idleTimerDisabled = YES;
return YES;
}
-(BOOL)eliminateTempView // example, when the user clicks on the button
{
theTemporaryView.view.hidden = YES;
[theTemporaryView release];
}
Hope it helps!
I've got a button on a view. When I click on it, it should load another view, one with a novigation controller. So far I've got this, the button calls this method:
-(IBAction)loadOptionsView:(id)sender {
if (self.optionsRootController == nil) {
//optionsRootController is declared as: UINavigationController *optionsRootController;
optionsRootController = [[UINavigationController alloc] init];
//Options is a UIViewController
Options *myOptions = [[Options alloc] initWithNibName:#"OptionsMenu" bundle:nil];
[optionsRootController pushViewController:myOptions animated:NO];
[myOptions release];
}
[self.view addSubview:optionsRootController.view];
}
What happens when I click the button is that it loads the xib file OptionsMenu on top of the current screen, but there's a gap at the top of the size of the status bar, so I can see the view below. Any help? What's the right method to load a new view that contains a navigation controller?
Thank you all!
I solved this issue by placing after:
[optionsRootController pushViewController:myOptions animated:NO];
this line:
[optionsRootController.view setFrame: [self.view bounds]];
Nice and easy!
I think UINavigationController's designated initializer is
- (id) initWithRootController:(UIViewController *)rootController
So your code above would be better expressed as
//optionsRootController is declared as: UINavigationController *optionsRootController;
//Options is a UIViewController
Options *myOptions = [[Options alloc] initWithNibName:#"OptionsMenu" bundle:nil];
optionsRootController = [[UINavigationController alloc] initWithRootController: myOptions];
[myOptions release];
Is the VIew in your nib the right size for the whole screen? Try turning off the simulated status bar in IB.