It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 11 years ago.
I'm developing a first iPhone app for iOS 4.x/5.0 and have some confusions on how to comply with the recommended Apple guidelines. I have also attached code snippet.
Here is the scenario:
When the app loads, I want to show the following functionalities in the bottom of the screen: Test, Settings. My first question is do I have to go with a UISegmentedControl or UITabBar? The trickiest part is I don't want the first "Test" tab/button to be selected automatically. I want the user to select the tab/button. Until that happens, I want a timer that runs showing some text. I tried to use a UITabBar and when the app loads, the first "Test" tab is selected and the associated ViewController is shown by default. I circumvented this by pushing a "root view controller" in the "didFinishLaunchingWithOptions" method in the AppDelegate.m. This works and when I click on the "Scores" tab, it pops the "root view controller" and pushes the "test view controller". But if I select the "Settings" tab immediately after the app loads and click on the "Test" tab, the view controller for the "Test" tab is not loading at all, but the "main view controller" is still displayed. I also have a UINavigationController in place on the "Test" tab and I hide it in the "viewDidAppear" event. I also want to eliminate the animation (pushing back) when I click on the "Test" tab.
My confusions are:
Can I replace the UINavigationController with some other control to let the user click on a "Start/Stop" button (displayed on the top) when in the "test view controller"?.
Is there a click event on the tabs in the UITabBar for each of the tabs?
I wanted to do everything from code (except adding controls) to ViewControllers. It looks confusing to me to use IB to do the same thing. Is this is a bad approach?
The following is the code snippet:
AppDelegate.m
#import "NavTabTestAppDelegate.h"
#import "RootViewController.h"
#import "FirstViewController.h"
#import "SecondViewController.h"
#implementation NavTabTestAppDelegate
#synthesize window = _window;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
RootViewController *rootViewController = [[RootViewController alloc ] initWithNibName:#"RootViewController" bundle: nil];
[rootViewController.view setBackgroundColor:[UIColor blueColor]];
// [rootViewController setTitle:#"RootViewController"];
FirstViewController *firstViewController = [[FirstViewController alloc ] initWithNibName:#"FirstViewController" bundle: nil];
[firstViewController.view setBackgroundColor:[UIColor yellowColor]];
[firstViewController setTitle:#"FirstViewController"];
SecondViewController *secondViewController = [[SecondViewController alloc ] initWithNibName:#"SecondViewController" bundle: nil];
[secondViewController.view setBackgroundColor:[UIColor redColor]];
[secondViewController setTitle:#"SecondViewController"];
//create the navigation controller and use NavRootController as its root
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:firstViewController];
//create an array of views that will be passed to our tabbar
NSArray *viewsArray = [NSArray arrayWithObjects:nav, secondViewController, nil];
//Now create our tab bar controller
UITabBarController *tabbarController = [[UITabBarController alloc] init];
//then tell the tabbarcontroller to use our array of views
[tabbarController setViewControllers:viewsArray];
[nav pushViewController:rootViewController animated:NO];
//nav.view.hidden = YES;
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
//then the last step is to add the our tabbarcontroller as subview of the window
self.window.rootViewController = tabbarController;
return YES;
}
RootViewController.m (added the following code)
- (void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES animated:animated];
// NSLog(#"Inside RootViewController.m viewWillAppear %#", animated);
}
- (void) viewWillDisappear:(BOOL)animated{
// NSLog(#"Inside RootViewController.m viewWillDisappear %#", "Done");
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:NO animated:NO];
}
FirstViewController.m (added the following code to prevent the animation but didn't work)
- (void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:NO];
[self.navigationController setNavigationBarHidden:NO animated:NO];
// NSLog(#"Inside FirstViewController.m viewWillAppear %#", animated);
}
- (void) viewWillDisappear:(BOOL)animated{
// NSLog(#"Inside FirstViewController.m viewWillDisappear %#", "Done");
[super viewWillAppear:NO];
[self.navigationController setNavigationBarHidden:NO animated:NO];
}
NSLogs throws exception when I click on a tab (BAD_ACCESS). Couldn't figure out why.
I come from a Windows developer background and I apologize for the long post. Please help.
Thanks.
My first question is do I have to go with a UISegmentedControl or
UITabBar? The trickiest part is I don't want the first "Test"
tab/button to be selected automatically.
I think you're missing the point of UITabBarController. Its job is to let the user select one of several different views, and it manages the view controllers corresponding to those views. One of the views will always be selected -- it really doesn't make sense to have no tab selected. If you want the "tabs" to do something other than select a view, you should use something else, such as UIToolbar or perhaps UISegmentedControl.
Can I replace the UINavigationController with some other control to let the user click on a "Start/Stop" button (displayed on the top)
when in the "test view controller"?.
I had a hard time grokking what you're trying to do with the navigation controller, so it's hard to say whether or not you can replace it. You should understand, though, that UINavigationController is a view controller, not a control. If you're just talking about the navigation bar that's provided by the navigation controller, then sure, you can display that or not depending on your preference.
Is there a click event on the tabs in the UITabBar for each of the tabs?
The tab bar delegate should implement the UITabBarDelegate protocol, which includes – tabBarController:didSelectViewController:.
I wanted to do everything from code (except adding controls) to
ViewControllers. It looks confusing to me to use IB to do the same
thing. Is this is a bad approach?
Depends on who you ask. Most experienced Objective-C programmers use IB when it's appropriate, i.e. just about any time you need to define a relatively static user interface.
Some people prefer not to use IB, but it seems to me that most of those folks never really took the time to learn how to use IB. You should do whichever you prefer.
I'd say that avoiding a useful tool because you don't understand it might be reasonable in the short term, but is a poor approach over the long term. When you're just learning to program on a whole new platform, it's quite reasonable to limit the number of things you need to know. IB really isn't complicated, though, and it's very useful. If you don't use it right now, make a note to yourself to spend some time working with it in the future.
Related
I need to implement something like the Path menu, which is globally available within the app no matter which screen user stays.
Please note I'm not asking how to implement the animation/styling things, I'm just curious about the proper way to layout the menu cross view controllers.
The approach I'm currently taking is:
Create a container view controller, make it as the
rootViewController of the app
Add functional view controllers as child controllers to the root one
Create global menu as a view, insert it as a subview to root view
controller's view, make it appear above other subviews
when user select a menu item in the global menu, I need to bring the
corresponding functional view controller's view to the front, but
still underneath global menu view
The downside of this approach is:
Presenting modal view controller will block the global menu
Have to pre-load every functional view controllers upfront
In short, I managed to achieve the UI/UX expectation, but technically, I feel I'm doing it wrong. Has anyone got similar project experience, please share your thoughts.
There are two solutions,
You could add your a global menu into AppDelegate,
(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOption
Then you could add your global menu into navigation controller view, such as,
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
self.viewController = [[HomeViewController alloc] initWithNibName:nil bundle:nil];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
self.navigationController.delegate = self.viewController;
self.window.rootViewController = self.navigationController;
// Your Global Menu
UIButton *myButton ...
[self.navigationController.view addSubview:myButton];
[self.window makeKeyAndVisible];
return YES;
}
You could create a BaseViewController, and add your global buttons into BaseViewController. Then all other viewcontrollers inherit BaseViewController. So some view controller could have global menu. If some view controllers don't want global menu, just inherit the normal UIViewController.
Such as,
#import "GlobalMenuView.h"
#interface BaseViewController : UIViewController
{
UIButton *btnMenu;
GlobalMenuView *globalMenu;
}
#end
Then the view controller which wants global menu just do,
#import "BaseViewController.h"
#interface YourOtherViewController: BaseViewController
{
}
#end
You could probably add it straight onto the UIWindow after making sure the the main UIViewController has already been added?
I am probably not any help now, but there is also a better solution to what you want to achieve. What you could do is subclass a UIView object, and then in your app delegate class, in your
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
method, you can insert the following code
[self.window insertSubview:(UIView) aboveSubview:(UIView)];
and that should give you the thing you want to accomplish :)
Hope that helps any
I'm fairly new to Objective-C and iPhone programming so I apologize if this is a newbie question. I have a simple application that needs to go from one view, to another. The first view is a UIViewController. I set up the xib file in IB (i.e. dragged some buttons onto the window) and hooked up all the buttons (which all work). I then created another xib file and class (also a UIViewController) and hooked them up. When a button is pressed in the first view I want to load the second view. Here's the code that is supposed to be pushing the view:
-(IBAction)createAccount:(id)sender{
CreateAccountViewController*acctView = [[CreateAccountViewController alloc] initWithNibName:#"CreateAccount" bundle:nil];
[self.navigationController pushViewController:acctView animated:YES];
[acctView release];
}
But this does nothing. When I put print statements in the createAccount method those are printed (I can click the button any number of times and it never crashes) but the acctView is never pushed. When I print out the value of self.navigationController it returns null. It's even stranger because if I present the acctView modally then it works.
-(IBAction)createAccount:(id)sender{
CreateAccountViewController*acctView = [[CreateAccountViewController alloc] initWithNibName:#"CreateAccount" bundle:nil];
[self presentModalViewController:acctView animated:YES];
[acctView release];
}
This works just fine, but I don't want to use the view modally. I'm completely lost here. In the past couple of hours I've come across a lot of posts saying to do something with a UINavigationController and hook that up to my view, but how do I do that? Any help is greatly appreciated! Thanks.
It seems you haven't created a UINavigationController for your app.
Best thing would be starting from scratch with a new Xcode project, taking care of choosing a Navigation Based application. In this way you will get almost everything already set up for you.
If you don't like this approach, you can create programmatically your UINavigationController. Here you find a tutorial for doing that.
If you prefer more straight-to-the-point instructions, here they are:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
MainPageDialog *overviewViewController = [[MainPageDialog alloc] initWithNibName:#"MainPage" bundle:nil];
self.navigation = [[[UINavigationController alloc] initWithRootController:overviewViewController] autorelease];
[overviewViewController release];
[window addSubview:[navigation view]];
[self.window makeKeyAndVisible];
return YES;
}
whereby self.navigation is a retained property in your appDelegate.
EDIT:
This answer was quite old, therefore an update:
If you are using ARC, you should be using a strong (vs. retain) property and you would not need the autorelease;
if you target iOS > 4.0 (which is also implied by the above point), you can use the rootViewController property in UIWindow and say:
MainPageDialog *overviewViewController = [[MainPageDialog alloc] initWithNibName:#"MainPage" bundle:nil];
self.window.rootViewController = [[[UINavigationController alloc] initWithRootController:overviewViewController] autorelease];
[overviewViewController release];
[window addSubview:[self.window.rootViewController view]];
[self.window makeKeyAndVisible];
without the need for any navigation property.
I'm trying to use a UINavigationController but I'm uncertain how. Up till now (for about a year), I've been using presentModalViewController and dismissModalViewController to present/dismiss view controllers.
So, this is what I did. My main view controller (the first one that shows on launch) is called MainViewController, and it extends UIViewController.
So I made this launch function in my app delegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
MainViewController *controller = [[MainViewController alloc] init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:controller];
[self.window addSubview:navigationController.view];
[self.window makeKeyAndVisible];
return YES;
}
And in my MainViewController's viewDidLoad method:
- (void)viewDidLoad {
[super viewDidLoad];
self.title = #"Title";
self.navigationController.navigationBar.tintColor = [Constants barColor];
....more code...
}
But, in my MainViewController, I'd like to present another view controller called SecondViewController, which needs a UINavigationBar with a back arrow button. So do I make SecondViewController extend UIViewController and do the same thing by setting the title and backButton in the viewDidLoad method? And how do I present it? What should I do to accomplish this?
You'll need to set a root view controller up, it's easiest starting from the apple template.
Here's where the magic happens:
UIViewController *controller = [[UIViewController alloc] initWithNibName:#"MyNib" bundle:nil];
[self.navigationController pushViewController:controller animated:YES];
[controller release];
The nav controller does all the work for you (back buttons, titles, animations) - it keeps track!
My workflow is this:
Setup MutableArray in the viewDidLoad, add controllers to it, e.g:
NSMutableArray *array = [[NSMutableArray alloc] init];
MyCustomViewController *customView = [[MyCustomViewController alloc] initWithNibName:#"nib" bundle:#"nil"];
customView.title = #"Second Level";
[array addObject:customView];
self.controllers = array;
Then in your delegate:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger row = [indexPath row];
UIViewController *childControllerToBe = [controllers objectAtIndex:row];
[self.navigationController pushViewController:childControllerToBe animated:YES];
}
This, along with a lot more can be learnt by reading a decent beginner book such as Beginning iPhone Development
Also, apple docs are always good :)
UINavigationController is a subclass of UIViewController, but unlike UIViewController it’s not usually meant for you to subclass. This is because navigation controller itself is rarely customized beyond the visuals of the nav bar. An instance of UINavigationController can be created either in code or in an XIB file with relative ease.
Please visit "How to add UINavigationController Programmatically"
You should Push it onto the navigation stack.
This Lecture by Stanford's iPhone Course will teach you a lot about Navigation Bars. (It's a quick read)
Basically at the heart of it you need this code:
[self.navigationController pushViewController:SecondView];
You can use PopViewController to go back programmatically, but the Back Button is automatically created.
Here's some source code from the Lecture. It covers exactly what you are having issues with.
I have created a new application using the View Based Application Template in xCode.
My first view, which displays on loading the app, is a button based menu. One of the buttons (Make) should load a new navigation stack using a NavigationViewController. There are other buttons that when implemented will do other things outside of NavigationViewController's scope.
I would like to be able to click Make and open and display a new navigation controller.
From ViewController.m:
-(IBAction)makeStory:(id)sender{
NSLog(#"makeStory:");
navController = [[UINavigationController alloc] init];
makeStoryTableViewController = [[MakeStoryTableViewController alloc] initWithNibName:#"MakeStoryTableViewController" bundle:nil];
[navController pushViewController:makeStoryTableViewController animated:YES];
}
I have created a NavigationViewController in the opening ViewController.h file:
#import <UIKit/UIKit.h>
#import "MakeStoryTableViewController.h"
#interface StoryBotViewController : UIViewController {
UINavigationController *navController;
MakeStoryTableViewController *makeStoryTableViewController;
}
- (IBAction)makeStory:(id)sender;
#end
I know I'm missing something because when I call pushViewController nothing happens - I think that somehow I have to attach the NavigationViewController to the ViewController that makeStory: is in.
For reference, my app delegate header declares the view controller in the #implementation as follows:
UIWindow *window;
StoryBotViewController *viewController;
with the appropriate #synthesize in the .m of the app delegate
#synthesize window;
#synthesize viewController;
How do I push a NavigationStack on from my opening view controller?
Please forgive me if the question is a little vague, I'm happy to provide more information if you need it. It's my first time questioning on stackoverflow and I'm obviously a bit of a newbie with the iPhone SDK.
you had it almost. But you forgot to add the NavigationController to your view.
[self.view addSubview:navController.view];
Add this in your IBAction.
EDIT:
but much likely this is not what you want, because you can't navigate back to your very first viewController. If you want to navigate back to the first viewController set up your project like in the navigation-based template. You can to this programmatically to:
Move all UINavigationController stuff from the header file of the viewcontroller to the app delegate header. And change your app delegate implementation to something like this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
navController = [[UINavigationController alloc] initWithRootViewController:viewController];
// Add the view controller's view to the window and display.
// [window addSubview:viewController.view];
[window addSubview:navController.view];
[window makeKeyAndVisible];
return YES;
}
make sure to release navController in dealloc
then replace your IBAction with something like this:
- (IBAction)makeStory:(id)sender {
makeStoryTableViewController = [[MakeStoryTableViewController alloc] initWithNibName:#"MakeStoryTableViewController" bundle:nil];
[self.navigationController pushViewController:makeStoryTableViewController animated:YES];
}
if you don't like to display the navigationbar in your first viewcontroller hide it, but make sure to unhide it if you push other items on the stack. self.navigationController.navigationBar.hidden = ...
First off I'm new at programming. I'm creating an app with one navigation bar controller. The app is pretty basic except for a quiz section that is comprised of 12 xibs. As the users takes the quiz a new xib is pushed onto the stack. I want to create a button that takes the user back to the home screen if they do not want to complete the quiz. The back button takes them to the previous xib which could be 11 deep. Is it possible to dismiss the modal views and reload the rootView controller?
Here's the code from my delegate
#synthesize window;
#synthesize navigationController;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Override point for customization after application launch
[window addSubview:[navigationController view]];
[window makeKeyAndVisible];
}
-(void)dealloc {
[window release];
[navigationController release];
[super dealloc];
}
This is how I'm pushing new xibs onto the stack
-(IBAction) showTesting: (id)sender {
Testing *varTesting = [[[Testing alloc] initWithNibName:#"Testing" bundle:nil] autorelease];
[[self navigationController] pushViewController:varTesting animated: YES];
}
Any help would be greatly appreciated. Thanks
You can just call popToRootViewControllerAnimated: to go back to the first view controller.