In my iPhone application I want to make a page/view where the user can add notes.. essentially write something and then save it...
similar to what the Notes app offers on the iPhone... but at a basic level...
I was thinking of something simple like a tableview with a "+" button on the navigation bar that lets the user add a note.
I have googled every possible thing I could think of.. :(
Could someone show me how I would go about implementing this in my view controller?
(I know it seems very simple but I'm new to programming for the iPhone - hence why I'm struggling...)
You will want to add a barbuttonitem to the navigation bar and set the action to method that launches your Note viewController with a new note. The easiest way to do all that is to use Interface Builder to add the button and hook up the action to a custom method that looks something like this:
- IBAction newButtonPressed:(id)sender
{
NoteViewController *noteVC = [[NoteViewController alloc] initWithNibName:#"NoteViewController" bundle:nil];
[self presentModalViewController:noteVC animated:YES];
[noteVC release];
}
If you want to add the BarButtonItem from code you can do this in your viewDidLoad method:
UIBarButtonItem *newButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(newButtonPressed:)];
self.navigationItem.rightBarButtonItem = newButton;
[newButton release];
Note - the above code assumes your View Controller is called NoteViewController and has a Nib called NoteViewController, if you are doing some other form of initialization, then do it there, the important code is the presentModalViewController.
If instead of the modalview approach, you would like a more navigation like entrance (with back button functionality, etc.) you can use the following method instead:
- IBAction newButtonPressed:(id)sender
{
NoteViewController *noteVC = [[NoteViewController alloc] initWithNibName:#"NoteViewController" bundle:nil];
[self.navigationController pushViewController:noteVC animated:YES];
[noteVC release];
}
Related
So I have an interesting design question regarding an app I'm developing for the iPhone. I am creating an app that manipulates images, and there are different types of manipulations that can be performed. So the user opens the app, and selects what type of manipulation they want to perform, and are taken through a step by step process to perform the manipulation.
A lot of the manipulations are similar, so code can be reused here. So instead of creating a view controller for each window of each manipulation, I decided to create one view and one view controller. The view contains the steps of each image manipulation, and each time it is incremented to the next step, it reorganizes itself appropriately. The view controller is controlled by a navigation controller, and each time the user advances to the next step of whatever image manipulation they're trying to perform (ie pushed a new view controller on the stack), I make a copy of my view object, set it to reorganize its components to the appropriate step, then send it to the new view controller which will display it.
So my question is this, for some stages of the manipulations, I need to add some buttons to a universal toolbar that is attached to view controller (since this is a modal view, this tool bar will have a home button that will enable the user to exit back to the main screen). Basically, I have a couple of questions on how I should approach this:
1) Should I simply add the toolbar to the view that I'm using, instead of the view controller. If so, how would I have the home button on the toolbar exit the modal view?
2) Should I keep the toolbar on the view controller, and have my view return a set of buttons to be added to it when the view loads? Then I guess I would have to list all of my action methods in my view controller?
3) Should I keep the toolbar on the view controller, but send a pointer from the toolbar to my view object, then add the buttons within my view class? Would I be able to add my action methods in my view class then?
Anyhow, sorry if this is complicated, and if you have any follow up questions please let me know.
1) Ok.
For dismissing, does your view have a pointer to the view controller? How about something like this:
[self.viewController.parentViewController dismissModalViewControllerAnimated:YES];
Not sure if I understand exactly how your hierarchy is organized. That's just my guess.
2) That seems kludgy to me. You'd have to define some sort of data structure that describes what the view wants in a button, make a list of them. The view controller has to request that list, go through them.
3) That seems like the best option. But I wouldn't have your view directly add subviews to the toolbar. Create a ToolbarView custom view. Give it some kind of addButton method, with parameters that describe what essential attributes you want the button to have, like title and the target and action maybe. Let the ToolbarView decide what it looks like, where it's positioned, etc.
Can your action methods go on your view class? Yeah I guess, but they shouldn't. The recommended iPhone design pattern is that views shouldn't do anything, they should just show things. Methods that do things should be on view controllers, even if the only thing they do is change what views are being shown.
I finally came up with a solution for this. What I did was create a universal view controller called UIMainViewController that obviously inherits from UIViewController. I implement the toolbar like follows:
- (void) viewDidLoad
{
[super viewDidLoad];
[self assembleToolbarButtons];
[[self navigationController] setToolbarHidden:NO];
[self setToolbarItems: toolbarButtons];
[[[self navigationController] toolbar]setBarStyle:UIBarStyleBlack];
}
- (void) assembleToolbarButtons
{
NSMutableArray *toolbarButtonsTemp = [[NSMutableArray alloc] init];
[self setToolbarButtons: toolbarButtonsTemp];
[toolbarButtonsTemp release];
if ([self mode] == UIMainViewControllerMainMode)
{
UIBarButtonItem *createAPictureButton = [[UIBarButtonItem alloc] initWithTitle:#"Create" style: UIBarButtonItemStyleBordered target:self action:#selector(loadCreateAPictureModalViewController)];
UIBarButtonItem *accountButton = [[UIBarButtonItem alloc] initWithTitle:#"Account" style: UIBarButtonItemStyleBordered target:self action:#selector(loadAccountModalViewController)];
UIBarButtonItem *helpButton = [[UIBarButtonItem alloc] initWithTitle:#"Help" style: UIBarButtonItemStyleBordered target:self action:#selector(loadHelpModalViewController)];
[[self toolbarButtons] addObject: createAPictureButton];
[[self toolbarButtons] addObject: accountButton];
[[self toolbarButtons] addObject: helpButton];
[createACaptionButton release];
[accountButton release];
[helpButton release];
}
else
{
UIBarButtonItem *homeButton = [[UIBarButtonItem alloc] initWithTitle:#"Home" style: UIBarButtonItemStyleBordered target:self action:#selector(exitModalViewController)];
[[self toolbarButtons] addObject: homeButton];
[homeButton release];
}
}
-(void) loadCreateAPictureModalViewController
{
CreateAPictureViewController *createAPictureViewController = [[CreateAPictureViewController alloc] initWithMode:UIMainTableViewControllerModeModal];
UINavigationController *createAPictureNavController = [[UINavigationController alloc] initWithRootViewController: createAPictureViewController];
[[createAPictureNavController navigationBar] setBarStyle:UIBarStyleBlack];
[self presentModalViewController:createAPictureNavController animated:YES];
[createAPictureNavController release];
[createAPictureViewController release];
}
-(void) loadAccountModalViewController
{
AccountViewController *accountViewController = [[AccountViewController alloc] initWithMode:UICaptionDistractionTableViewControllerModeModal];
UINavigationController *accountNavController = [[UINavigationController alloc] initWithRootViewController: accountViewController];
[[accountNavController navigationBar] setBarStyle:UIBarStyleBlack];
[self presentModalViewController: accountNavController animated:YES];
[accountNavController release];
[accountViewController release];
}
-(void) loadHelpModalViewController
{
HelpViewController *helpViewController = [[HelpViewController alloc] initWithMode:UICaptionDistractionTableViewControllerModeModal];
UINavigationController *helpNavController = [[UINavigationController alloc] initWithRootViewController: helpViewController];
[[helpNavController navigationBar] setBarStyle:UIBarStyleBlack];
[self presentModalViewController: helpNavController animated:YES];
[helpNavController release];
[helpViewController release];
}
-(void) exitModalViewController
{
[self dismissModalViewControllerAnimated:YES];
}
So for my app, on each viewcontroller it will have a toolbar at the bottom that have the basic buttons for creating a picture, accessing the account, or accessing help. If one of these buttons is accessed, it will launch a modal view which will have the home button to exit the modal view (when the UIMainViewController is created, one of it's parameters tells it which mode it is in, and thus which toolbar buttons to add.
But the main thing is I created a class mutablearray varialbe to store the toolbar buttons and then the buttons are created in "assembleToolbarButtons". Now any class that inherits from UIMainViewController can override the assembleToolbarButtons in order to add it's own buttons on top of the main ones that have already been added.
As far as what I mentioned initially in using one UIView and having it reorganize itself, and only one uiviewcontroller, I avoided this and instead just created separate view controllers for each step and separate views so as to adhere to MVC more.
I have following code which add BackButton on my view's navigation item's tabbar. It works fine.
// Add back button
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:#"Back" style:UIBarButtonItemStylePlain target:nil action:nil];
[view.navigationController setNavigationBarHidden:NO animated:YES];
view.navigationItem.backBarButtonItem = backButton;
view.navigationController.navigationBar.barStyle = UIBarStyleBlack;
[backButton release];
I use following line to navigate to my new view controller but it gets presented with default animation.
[view.navigationController pushViewController:viewController2 animated:YES];
I want to change the way it gets presented so I tried to do it following way.
[viewController2 setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
[view.navigationController presentModalViewController:viewController2 animated:YES];
This works fine but I lost my BackButton..!! Is there anyway to present my new view controller with specific transition style and also keep my back button as is?
Thanks.
I found the answer to your question. Put a navigation bar on your viewController2 and add a bar button to it using either interface builder or using code. Then in the action of button press
In your viewController2.m write this function and link it up with the button press if you have added the bar button through interface builder.
-(void) backButtonPressed : (id) sender
{
[self dismissModalViewControllerAnimated:YES];
}
This should solve your problem.
Doing a pushViewController will carry forward the navigationBar and all for you but in your case presenting a viewController as modalViewController will not give you the navigationBar by default so you have to add it manually in your modalViewController which is viewController2 in your case.
Please let me know if you are still facing problems. We can fix it soon and save you some time and frustration.
Cheers!!!
I am trying to show the UIToolBar in the RootView of a UISplitView application, the code is the following:
self.navigationController.toolbarHidden = NO;
UIBarButtonItem *refreshItem = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh
target:self
action:#selector(refresh:)];
self.toolbarItems = [NSArray arrayWithObjects:refreshItem, nil];
[refreshItem release];
However, what I see is:
There's black bar on top (I don't know where this came from, I don't need this) also the bar at the bottom, is there a way to resize it?
What I want is to get something like this:
Using something like this you can add a bar button item to the top of the controller:
UIBarButtonItem *refreshItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:#selector(refresh:)];
self.navigationItem.leftBarButtonItem = refreshItem;
[refreshItem release];
You will make the button appear in the main view controller's title bar, as it's meant to be.
If you want to make the button appear in the bottom of the navigation controller you could try using this approach, instead:
UIBarButtonItem *refreshItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:#selector(refresh:)];
[self setToolbarItems:[NSArray arrayWithObjects:refreshItem, nil animated:YES]];
[self.navigationController setToolbarHidden:NO]; //optional, don't remember if it's required ...
[refreshItem release];
For this piece of code to work correctly the side controller has to be a UINavigationController, otherwise you wouldn't be able to create and handle the toolbar. I tried this approach in a clean project and the toolbar renders perfectly.
I had the same issue and Just fixed it, Due to moving the code out of the Viewdid Load to lower down the Page,
As I had previous put in
- (UIBarButtonItem *)barButtonItem {
Moving the Code You used to under that, Worked and fixed the issue
Stewart
Just a note for anybody else who stumbles upon this question. I was having the same issue as adit. The problem turned out to be I was setting up and unhiding the toolbar in the viewDidLoad method instead of the viewWillAppear method. Those gaps are caused by setting up the toolbar before the view knows it's being displayed in landscape mode.
The safest and easiest solution is to setup the UINavigationController to display the toolbar and navigation bar in Interface Builder.
If it looks as expected in IB, it is very unlikely it will change at run-time.
If the toolbar is to be shown/hidden when navigating you should add the cod to do so in viewWillAppear: and allways call the super implementation, or unexpected things may occurs. Something like this tends to give the best results in a consistent manner:
-(void)viewWillAppear:(BOOL)animated;
{
[super viewWillApplear:animated];
[self.navigationController setToolbarHidden:NO
animated:animated];
}
Also make sure to show/hide the toolbar as need in viewWillAppear: for all view controllers in your navigation stack for best result.
I know that it could seem strange but i need to add a back button on the navigation Bar of the first navigationController's view. I tried like this:
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:#"Foo" style:UIBarButtonItemStyleBordered target:self action:#selector(foo:)];
self.navigationItem.backBarButtonItem=backButton;
if instead of backBarButtonItem i write leftBarButtonItem the button is showed. My problem is that i need an arrow button as the normal back button. Is this possible?
Usually this works out of the box, but sometimes with modal views / action sheets you may need this. Just before you instantiate your viewcontroller and push it onto navigationcontroller stack, try
UIBarButtonItem *newBackButton = [[UIBarButtonItem alloc] initWithTitle: #"Back" style: UIBarButtonItemStyleBordered target: nil action: nil];
[[self navigationItem] setBackBarButtonItem: newBackButton];
[newBackButton release];
DetailViewController *detailVC = [[DetailViewController alloc]init];
[self.navigationController pushViewController:detailVC animated:YES];
[detailVC release];
I don't think you can do that on the first NavigationController view, because you need to set the backBarButtonItem property in the parent controller, before the child controller is pushed. Also, according the to the Apple docs, the target & action of the backBarButtonItem must be nil.
This question about creating a left-arrow button on a UIToolbar may give you some ideas of how you could work around this using a custom image (for the leftBarButtonItem).
or you could also do the following - I prefer this method. I got this from a different post.
Use following psd that I derived from http://www.teehanlax.com/blog/?p=447
http://www.chrisandtennille.com/pictures/backbutton.psd
Then I just create a custom UIView that I use in the customView property of the toolbar item.
Works well for me.
Hope that helps a little
Of course you can do this. You just need to change the leftBarButtonItem's title to back
then you will get a nice left arrow button with the title back. Then you just change the selector to actually perform a method when the button is clicked. So #selector(foo:)
Here some code on how to achieve the above:
self.navigationItem.leftBarButtonItem.style = UIBarButtonItemStyleDone;
self.navigationItem.leftBarButtonItem.title = #"Back";
self.navigationItem.leftBarButtonItem.target = self;
self.navigationItem.leftBarButtonItem.action = #selector(endTextEnteringButtonAction:);
Let me know if that helps.
Apple Document says:
When this navigation item is immediately below the top item in the stack, the navigation controller derives the back button for the navigation bar from this navigation item.
So If your navigation item is the top of the Stack (as we are talking here) you can't add the back button to the navigation controller, simply because no place he can navigate back to it because it's the top item in the stack.
Updated Answer :
After I searched I found work a round to make a back button in your root view controller in Navigation controller in these link
It's very simple :)
[self.navigationItem setHidesBackButton:YES animated:YES];
UIBarButtonItem* backButton = [[UIBarButtonItem alloc] initWithTitle:#"Start" style:UIBarButtonItemStyleBordered target:self action:#selector(initializeStuff)];
self.navigationItem.leftBarButtonItem = backButton;
For some reason, if I try to go back to the main menu using the back button on the upper left corner, only the title returns to the previous menu, but not the view controller. View controller would return to the previous menu only if I explicitly call popViewControllerAnimated using some other button.
Is there anyway to solve this? I think I've coded something wrong. Tried googling but couldn't find any cases like mine.
I'm getting the exact same problem. Here is my code:
- (IBAction) showGameView:(id) sender {
gameView = [[TCGameViewController alloc] initWithNibName:#"TCGameViewController" bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:gameView animated:YES];
[gameView release];
}
And when I am done with gameView, I do this:
[self.navigationController setNavigationBarHidden:NO animated:YES];
But all it does when I push the 'back' button is cycle through the navigation bar, but never pops the view. I don't even know how to debug it.
In my other view, "infoView" I call the same code as before except the NavBar is never hidden, but it works just fine.
helps!
This problem can occur when you override the following method in your custom view controller:
- (UINavigationItem*)navigationItem
But you don't specify a UIBarButtonItem for the leftBarButtonItem property of the returned UINavigationItem.
If you use a custom navigationItem, and want the standard back button functionality, you could add a method as follows (remember that every UIViewController has a reference to the navigationController that containts it):
- (void)backButtonTapped
{
[self.navigationController popViewControllerAnimated:YES];
}
And then setup part of the custom navigationItem as follows:
- (UINavigationItem*)navigationItem
{
UIBarButtonItem* newLeftBarButton = [[UIBarButtonItem alloc] initWithTitle:#"Back"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(backButtonTapped)];
UINavigationItem* navigationItem = [[[UINavigationItem alloc] init] autorelease];
Hope this helps.