Need a really simple navigation controller with a table view inside a tab bar controller - objective-c

I have an app with a tab bar controller (2 tabs). In one tab view controller, a button leads to an alert window. I want one button of the alert window to call a table view containing possible answers. I want that table view to have a done button and a title. I think that means a navigation controller has to be used. But most everything I can find on navigation controllers assumes a much more complicated situation. Here's part of the alert window logic:
-(void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 2) {
AnswersViewController *aVC = [[AnswersViewController alloc] init];
[self presentViewController:aVC
animated:YES
completion:NULL];
}
}
And AnswersViewController looks like this:
#interface AnswersViewController : UITableViewController
#end
#implementation AnswersViewController
- (id) init
{
self = [super initWithStyle:UITableViewStylePlain];
return self;
}
- (id) initWithStyle:(UITableViewStyle)style
{
return [self init];
}
- (void)viewDidLoad
{
[super viewDidLoad];
[[self view] setBackgroundColor:[UIColor redColor]];
}
#end
This code all works as expected (an empty red UITableView appears).
Two questions I guess: 1. Is there a simple modification to what I have that can give me a done button and title in my table view? 2. If I have to go to a navigation controller (probably), how can I make a bare-bones navigation controller with a done button and title and embed the table view within it? Oh, and I want to do this programatically. And I think I prefer the done button and title to be in the navigation bar, no tool bar desired. Thanks!

To get what you are looking for, you do need to use a UINavigationController. That will provide the UINavigationBar where you can display a title and also buttons.
To implement this with a UINavigationController, you want to do smoothing like this (assuming you are using ARC, so you don't need to worry about memory management):
-(void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 2) {
AnswersViewController *aVC = [[AnswersViewController alloc] init];
//Make our done button
//Target is this same class, tapping the button will call dismissAnswersViewController:
aVC.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(dismissAnswersViewController:)];
//Set the title of the view controller
aVC.title = #"Answers";
UINavigationController *aNavigationController = [[UINavigationController alloc] initWithRootViewController:aVC];
[self presentViewController:aNavigationController
animated:YES
completion:NULL];
}
}
Then you would also implement - (void)dismissAnswersViewController:(id)sender in the same class as the UIAlertView delegate method (based on the implementation I have here).
Hope this helps!

Related

Pop controller after back bar button is pressed

I have a UINavigationController ans a chain of 3 simple controllers. Each one has a button. When press a button a next controller is Pushed. ViewController1 -> ViewController2 -> ViewController3. When I push a back button on the 3rd view i want to move to the first view. Using of backBarButtonItem is obligatory. Here is the code for second controller:
#import "ViewController2.h"
static BOOL isBackButtonPressed;
#implementation ViewController2
- (void)viewDidLoad {
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:#"back from 3" style:UIBarButtonItemStyleBordered target:nil action:nil];
[super viewDidLoad];
}
- (void)viewWillAppear:(BOOL)animated {
if (isBackButtonPressed) {
[self.navigationController popViewControllerAnimated:YES];
} else {
isBackButtonPressed = YES;
}
[super viewWillAppear:animated];
}
#end
But when I press back button on the third view I return to the second view instead of the first view. Could you help me to return to the first view pressing back button on the third view.
I tried suggestions from answers but they don't help.
Adding a selector to backBarButtonItem doesn't help because it is never called.
Adding a [self.navigationController popToRootViewControllerAnimated:YES] in viewWillDisappear methos also doesn't work. I don't know why. I think that the actual problem is how backBarButtonItem works.
Any other suggestions?
The behaviour I try to achieve exists in the calendar on iPhone. When you rotate iPhone to landscape you get to the weeek view. Then go to the event details, and rotate to the portrait. When you press back button you will get to a day view not to a week view, so a controller with weekview is skipped.
After countless number of tries my solution was simply not use backBarButtonItem! As whatever i do it always goes to previous viewController instead of calling its selector
Instead I use only leftBarButtonItem for navigation, as it guarantees calling my action.
Here an example
UIButton *backButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 27, 22)];
[backButton setImage:[UIImage imageNamed:#"backbutton"] forState:UIControlStateNormal];
[backButton addTarget:self action:#selector(backButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
This certainly calls backButtonPressed action.. This works both for IOS 6 and 7
No need to register a new selector for the back button, just do:
-(void)viewWillDisappear{
if ( [self.navigationController.viewControllers containsObject:self] )
//It means that the view controller was popped (back button pressed or whatever)
//so we'll just pop one more view controller
[self.navigationController popViewControllerAnimated:NO];
}
in your ViewController3 viewWillDisappear method
Try using this in your third view controller, this way you check if you have pressed the back button and directly pop to the root view controller which as you stated is your first view controller.
-(void) viewWillDisappear:(BOOL)animated {
if ([self.navigationController.viewControllers indexOfObject:self]==NSNotFound) {
[self.navigationController popToRootViewControllerAnimated:YES];
}
[super viewWillDisappear:animated];
}
I had the same problem as you beofre and fixed it like this:
You can capture the back button on the ViewController3 and before poping the view, remove ViewController2 from the navigation stack like this:
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:#"back from 3" style:UIBarButtonItemStyleBordered target:self action:#selector(customBackPressed:)];
}
-(void)customBackPressed:(id)sender {
NSMutableArray *allViewControllers = [NSMutableArray arrayWithArray: navigationController.viewControllers];
for (UIViewController *vc in viewControllers)
{
// If vc is ViewController2 type, remove it
}
navigationController.viewControllers = allViewControllers;
[self.navigationController popViewControllerAnimated:YES];
}
Because ViewController2 is not in the stack anymore, it will jump to ViewController1.
Also, if ViewController1 is the root view controller, you can just do:
[self.navigationController popToRootViewControllerAnimated:YES];

Objective-C: How to switch the NSView by button click

I have different xib files with NSViewController attached to them. (Screenshot below)
One of xib file called StartMenuViewController which has a button. I want to click that button and change the view to DetectingUSBViewController.(Screenshot below)
The IBAction of that button is in StartMenuViewController.m file.
And I use AppController.m to control my main xib view.(NSWindow + NSView) (Screenshot below)
When the application runs, I try to initialize the StartMenuViewController fist by doing the following thing in my AppController.m file.
-(void)awakeFromNib{
[self initialize];
}
-(void) initialize
{
#autoreleasepool {
//mainViewController is a NSViewController and _mainView is a NSView which connect with Custom View in main xib
self.mainViewController = [[[StartMenuViewController alloc]initWithNibName:StartMenuView bundle:nil]autorelease];
[_mainView addSubview:[_mainViewController view]];
}
}
It works fine and it will show the StartMenuViewController.xib on the window at first, but I do not know how to change the view after clicking the button(FIND USB DRIVE). I want the current view changes to DetectingUSBViewController.xib.
Simplest way possible, assuming you have tied your USB button properly in, do the following :
- (IBAction)usbButton:(UIButton *)sender {
DetectingUSBViewController *second = [[DetectingUSBViewController alloc] initWithNibName:#"DetectingUSBView" bundle:nil];
[self presentViewController:second animated:YES completion:nil];
}
load the DetectingUSBViewController in startMenuViewController as DetectingUSBViewController* v1 = [[ViewCont1 alloc] initWithNibName:#"ViewCont1" bundle:nil]; now add or replace the view as [v1 view] in view where you want to add/replace.
You need to hook up your button to send an IBAction
You need a 'View for DetectingUSBViewController.xib'
=> one way (iOS like) is to use a ViewController. Subclass NSViewController and then alloc init a DetectingUSBViewController
Add the view. Don't present the VC (as there is no such thing in OSX)
//button click action
- (IBAction)usbButton:(UIButton *)sender {
//! Retain the VC
Self.detectingUSBViewController = [[DetectingUSBViewController alloc] initWithNibName:#"DetectingUSBView" bundle:nil];
//add the view
[_mainView addSubview:[_detectingUSBViewController view]];
}

close modalvew controller and parentview

I am trying to open a modalview from a view like that,
SignupViewController *signUpView = [[SignupViewController alloc] initWithNibName:#"SignupViewController" bundle:nil];
[signUpView setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
self.parentViewController.view.transform = CGAffineTransformMakeScale(1.3, 1.3);
self.parentViewController.view.alpha = 0;
[UIView animateWithDuration:.35 animations:^{self.parentViewController.view.alpha = 1.0; self.parentViewController.view.transform = CGAffineTransformMakeScale(1, 1);}];
[self presentModalViewController:signUpView animated:YES];
After login i am closing the modalview and redirecting to anther view, but the parentview is still there,
[self dismissViewControllerAnimated:YES completion:^{
ToolsViewController *gototoolpage = [[ToolsViewController alloc] initWithNibName:#"ToolsViewController" bundle:nil];
[self.navigationController pushViewController:gototoolpage animated:YES];
}
How to dismiss the parentview also. Any idea
You code looks a little confused. What do you intend by references to parentViewController? Check the docs - it is the containing viewController, not the previous or presenting viewController. In a NavigationController context this would be the UINavigationController. In a modal view context there is no parentViewController, but there is a presenting ViewController. I am not sure what you intend by all of those calls to self.parentViewController.
In any case you should really be sending the dismiss request back to your presenting viewController via a delegate so that it is completely clear where the pushViewController message is being passed from and to.
In the header file of your signUpViewController declare a protocol:
#protocol SignUpViewControllerDelegate
- (void) dissmissSignUpVC;
#end
then in your presentingViewController, after
SignupViewController *signUpView = [[SignupViewController alloc] initWithNibName:#"SignupViewController" bundle:nil];
add
[signUpView setDelegate:self];
and implement the delegate method with the same code you now have in your completion block:
- (void) dissmissSignUpVC {
ToolsViewController *gototoolpage = [[ToolsViewController alloc]
initWithNibName:#"ToolsViewController" bundle:nil];
[self.navigationController pushViewController:gototoolpage animated:YES];
}
In signUpView invoke the delegate's method to dismiss:
[[self delegate] dissmissSignUpVC];
Watch out for those stacked animations, I suspect that only the first will be performed (i.e. gototollpage animated:YES might as well be gototoolpage animated:NO)
Perhaps anyway you should reconsider your logic. I imagine the user might have a confusing experience if you do this under-the-hood manipulation of viewControllers. Better that there is a UI control for the user to navigate to toolsViewController so they understand where they are?

Why can't I dismiss the previous view on a navigation stack?

This is probably going to be very obvious, but here goes. I have two ViewControllers, one that shows the details of a person with a [+] button that opens up another ViewController that manages the edits of the Person. When the person about to be deleted, an alert is presented and if OK is selected, the edit view should disappear and the DetailView should also disappear/transition back to the PersonsListView (not shown in code below).
I can get the EditView to dismiss, but I can't get the DetailView to dismiss as well.
Any help is appreciated.
The two ViewControllers:
#implementation PersonDetailViewController
...
- (void)editPerson
{
PersonDetailEditViewController *editView = [[PersonDetailEditViewController alloc] initWithTenant:self.person];
[editView setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:editView];
[self presentModalViewController:navController animated:YES];
}
...
#end
and
#implementation PersonDetailEditViewController
...
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 1) {
[Person deletePerson:self.person];
NSError *error;
[self.person.managedObjectContext save:&error];
[[self navigationController] dismissModalViewControllerAnimated:YES];
// *** HERE I ALSO WANT TO DISMISS THE DETAILVIEW ***
}
}
...
#end
Assuming that PersonDetailViewController is presented in a navigation controller you should be able to do what you want by adding the following line:
[self.navigationController popViewControllerAnimated:YES];

How to signal when a view is done and returning?

I'm building an iphone app, and i have my first view call a second view when a button is pressed. The second view is a UIPicker with a button. When the button is pressed, I want to return the data from the UIPicker. How would i do this? Here is the code i have so far:
This is the Button that calls the subview
-(IBAction)DayView:(id)sender{
DayPickerViewController *DPView =[[DayPickerViewController alloc]
initWithNibName:nil bundle:nil];
[self presentModalViewController:DPView animated:YES];
//tried below, doesnt work
//[calc SetDay:[DPView Getrow]];
//DaysButton.titleLabel.text =#"%i",[DPView Getrow];
}
This is the pickerview's code:
-(IBAction)buttonPressed{
NSInteger row = [dayPicker selectedRowInComponent:0];
data = row;
[self dismissModalViewControllerAnimated:YES];
}
The approach you tried first works on Windows where you can open and close a modal dialog in a similar way that you enter and leave a function. However, iOS doesn't work like this.
The simplest approach is to add an instance variable in you second view that refers to the parent view. Then you can notify the parent view by directly calling an instance method:
Main view:
-(IBAction) dayView:(id)sender {
DayPickerViewController *dpView = [[DayPickerViewController alloc]
initWithNibName:nil bundle:nil];
dpView.parent = self;
[self presentModalViewController:dpView animated:YES];
}
-(void) viewController:(DayPickerViewController*)controller
didSelectRow:(NSInteger)row {
// the child view has been dismissed,
// do something with the selected row...
}
Child view:
#property(nonatomic, retain) WoWViewController* parent;
...
#synthesize parent;
-(IBAction) buttonPressed {
NSInteger row = [dayPicker selectedRowInComponent:0];
[self dismissModalViewControllerAnimated:YES];
[self.parent viewController:self didSelectRow:row];
}