I was wondering if you could help me. I am developing an app where I have five UIView Controllers, each with fields to be completed and filled in. At the bottom of the page I have created a bottom bar with five buttons, one for each controller.
What I want is the following: If a user has filled in half of lets say VC_1 and then goes to VC_2, fills in a few fields here, and then goes back to VC_1 or a new VC3, that the progress before is still there.
I have tried this using "presentViewController" on each button press, however what happens if I go back to 1 is that all fields are empty, probably because it throws the viewController on top of the current one. One way that the data is not deleted is if I use dismissViewController, however this always brings me back to VC_1 and would not work if I wanted to go back from VC_3 to VC2.
I hope my questions makes sense and that one of you could explain how I can achieve the above objective.
Cheers,
Lennaert
Here are two idea which can help
Create and use models that persist longer than any view controller.
It sounds like you should use a UITabBarController.
For idea 1, whenever you are storing data create a class separate from any view controller to hold the data. When you create an instance your view controller, assign that data object to the view controller. Then when the view loads, use the data in the data object to fill in the fields. When the user makes a change with any of the controls, update the data object. See Model-View-Controller.
For idea 2, using a tab bar controller will keep active instances of all your view controller. That way you will not need to create new instances of them.
Looks like UITabBarController is your friend. It manages showing and hiding of the views for you.
Instead of UITabBarController I think your best choice is a UIScrollView with big contentSize and pagingEnabled = YES. All in one viewController and you can customize the bottom bar as you like.
Hmm Couple things to consider. As Per Allen's comment, you might want to consider embedding your project in a UITabBarController:
Here's how to do it programmatically:
#property (nonatomic, strong) UITabBarController *tabBarController;
MyView * view = [[MyView alloc]initWithNibName:#"MyView" bundle:nil];
view.title = #"My Planner";
nav1 = [[UINavigationController alloc] initWithRootViewController:view];
nav1.tabBarItem.image = [UIImage imageNamed:#"nofill_star.png"];
self.tabBarController.viewControllers=[NSArray arrayWithObjects:nav1,nil];
OR
MyView * view = [[MyView alloc]initWithNibName:#"MyView" bundle:nil];
view.title = #"My Planner";
self.tabBarController.viewControllers=[NSArray arrayWithObjects:view,nil];
Or from your story board, go to editor embed in tab bar. Also check out NSUserDefualts. That's something to consider as well.
Related
Ive a project close to doing everything I need it to do. Its got a Main page which has four buttons that allow you to choose an option. Then a tableview page is launched from those options and displays a parsed XML feed from a website. You can then select one of the options in the table to see a detail view of the item, enquire about it, etc.
My problem is I need to add more elements to the TableViewController page, other than the tableview itself. I want a customized back button (not the navigation controller standard) plus some labels, images, etc.
In the TableViewController xib, the tableview itself fills the page. I cant resize it to add more elements above it. I can add a 'view' window seemingly above the tableview and put things in it. But it seems to add the view to the tableview. This means that when I scroll the table, the other elements like new back button, scroll away as part of the table.
So I'm led to wonder whether I need this page not to be a tableviewcontroller, but a viewcontroller, with a tableview inside it, as well as my other view with buttons, etc. Is that the right way to go? But if thats the case, then how do I instantiate the tableviewcontroller within code? Because my page will not be of that type anymore - it will be just a viewcontroller. But in code Im making a tableviewcontroller .. slightly scared by that route tbh.
Any illumination on this would be much appreciated, as various searches have left me none the wiser. Thanks.
To customize it, this is the way to go:
Change your class to be a view controller instead, which implements the TableViewDelegate and TableViewData Source protocols.
In the view didLoad of you controller, create the table view, set its delegate, data source, and any other properties you wish and add it as a subview to your view.
tableView = [[[UITableView alloc] init] autorelease];
tableView.delegate = self;
tableView.dataSource = self;
// .. Other customization
[self.view addSubview:tableView];
I suggest doing this programatically rather than IB.
Instead of a UITableViewController, you want a UIViewController that has an IBOutlet UITableView. Drag and drop a UITableView component from Storyboard and hook it up, and position it as needed on the screen. This UIViewController should implement the UITableViewDelegate and UITableViewDataSource methods.
Edit: Remember that a UITableViewController is just a subclass of UIViewController so you don't really have to get rid of all your code. :) You only need to make minor tweaks to your header and main file, and change the Storyboard to be a UIViewController instead of UITableViewController as I mentioned above.
View A has a button upon clicking it, we go to view B
View B does not retain a pointer to view A.
From view B, i'd like to load view A back (programmatically)
Effectively, i'd like to kill B and replace it with A.
I was thinking that the following should work but, it does not
Calling from View B
ViewController *main = [ViewController new];
[self addSubview:[main view]];
What am i missing please?
Personally I think the easiest way to do this would be by having a UIViewController with an IBOutlet to both UIView objects. You can add and design them both in the interface builder and just set one of them (view B) as hidden (it's a property in UIView).
Then, you could specify a button action to toggle the visibility of view B.
I must add though that there are constructs for implementing screen flows, such as the NavigationController. In your case, however, you might also consider the use of the presentModalViewController:animated: method.
It all depends really, but in general it's better practice to make a seperate UIViewController for each UIView in your application.
Hope this helps!
This sounds to me like you're looking for a navigation controller. You can easily take away a navigation controllers NavBar and take away the animations if you don't want them - but this would achieve exactly what you're looking for.
my app has tabBarController with 3 views and in one of them I want to popup a web browser with the ability to return back to the application. To do that I am using UINavigationController.
In myAppDelegate.h I have defined the property UINavigationController *nav and in myAppDelegate.m I have #synthesize nav.
In the class where the webPopup function resides upon pressing the button my code comes to this function.
- (IBAction)showWeb:(id)sender {
myAppDelegate *app=[[UINavigationController alloc] initWIthRootViewController:self];
// because I want to return back to the same view
webController *web = [[webController alloc] initWithStyle:UITableViewStypeGrouped];
[app.nav pushViewController:web animated:YES];
app.nav.view.frame = CGRect(,0,320,430);
[self.view.window addSUbview:app.nav.view];
}
The web popup occurs but it is moved vertically, when I press "back button" my former view appears as well and it is also shifted vertically from what it was before.
After going back and forth few times the thing hangs.
Questions:
1. what can cause the shift?
2. how to avoid when I go "back" to see the title(test from the "back"button, I think this might cause a shift when I go back.
3. how to find out why it hangs after few attempt?
Thanks.
Victor
The line:
myAppDelegate *app=[[UINavigationController alloc] initWIthRootViewController:self];
makes no sense to me. Surely your compiler is warning you about that? What is "myAppDelegate" defined as? Classes should have a capital letter at the front, by the way.
Also, the line
[self.view.window addSUbview:app.nav.view];
is highly suspect, because the UIWindow for your application should have only one child UIView. You shouldn't just add more views willy nilly and expect things to work. It is possible to change the child UIView by removing the old one and adding a new one, but you don't seem to be doing that. Having more than one child UIView of UIWindow gets you into trouble very quickly -- for example, device orientation changing can break.
I'm not exactly clear as to why the app delegate (or the window for that matter) needs to be messed with at all to do what you are trying to do. Sounds like you should just be using standard Nav View Controllers and Web Views.
Also, you are alloc init'ing w/o any memory management.
I have a UINavigationController, complete with table view and associated magic.
The data I'm populating that table view from may have items from multiple categories, but the default view for the user will be one in which they are viewing all of the items, and then they have the ability to move backwards to a different table view that would allow them to select a different category, which would then return to the original table view with the appropriate data populated.
What's the proper approach for this? I can't seem to wrap my head around how I would make the navigation controller give me a back button (with appropriately wired up actions) without having come from a previous view in the stack (which wouldn't really exist at launch time if I start the user off from what is essentially the detail view, in stack terms.)
Also, the back button should be titled "Groups", not "Back", but that's really just an implementation detail. :)
Update: This issue finally manifested itself in production code, and here’s how I fixed it:
My UINavigationController is created in a nib, with the root view set as the “groups” view. Then, in my app delegate, I push the second view onto the stack while the app is launching.
That works fine for achieving the proper stack, but that doesn’t help with the back button title, because the navigation controller didn’t seem to want to grab the title from the root view, and instead was showing a back button with “Item” as the title.
So, on the pushed view, in viewDidLoad, I set:
self.navigationController.navigationBar.backItem.title = #"Groups";
and that did the trick.
The only potential downside of doing it this way would be if the pushed view controller were ever used in a scenario where the view below it wasn’t the groups view, but since the design of this particular application ensures that never happens, I’m accepting that failure. ;)
Another update:
I’m an idiot. Just set the title property of the navigationItem provided by the navigationController in Interface Builder, and boom, no issue. Or do it in code. It doesn’t matter, just don’t do it by setting the backItem.title way I show you above. That’s just dumb.
In your application delegate's .m file in the application:didFinishLaunchingWithOptions: method just push your view controllers like you normally would with[self.navigationController pushViewController:your_view_controller animated:YES]; and it should push them on before the application's first view controller appears.
To change the text of the button to Groups just call this before pushing your controllers.:
UIBarButtonItem *newBackButton = [[UIBarButtonItem alloc] initWithTitle: #"Groups" style: UIBarButtonItemStyleBordered target: nil action: nil];
[[self navigationItem] setBackBarButtonItem: newBackButton];
[newBackButton release];
I'm writing a program with a UITableView with and add button in the Navigation Bar which leads to an edit page. When you click on an item in the table, a view (rView) is pushed with information pertaining to that item. This view has an edit button that also leads to the edit page. Is there a way that I could put an if statement for the done button on the edit page that says "if parentViewController is the UITableView to go to rView, else popViewController?" I would assume there is a way to do this, but I'm not sure of the syntax to do so. Thanks
If I understand correctly you have a UINavigationController and push onto it
a UITableView
an "rViewController" (you can't push a view, must be a controller)
an "EditController"
But there is a possibility that step 2 is omitted and you go directly to the edit screen.
Now when the last controller is popped, you want to be able to always go to a "rViewController", even if it's not on the stack.
First of all, the parentViewController is NOT the previous controller on the stack, but rather the UINavigationController itself, so it has nothing to do with the present problem.
The way to do this is by setting the UINavigationController's viewControllers property explicitly with an NSArray. I haven't tried this but this should work:
When a user presses the "add" button, instead of just pushing the edit view controller, do something like:
NSArray* stack = navigationController.viewControllers;
navigationController.viewControllers = [stack arrayByAddingObject:rViewController];
[navigationController pushViewController:editController animated:YES];
(By the way, I would suggest not using names like "rView" except maybe for very short-lived local variables, like in a loop. Using descriptive names is very much part of the Cocoa idiom and will help you a lot in the long run.)