I have a three view tab bar app the second view of which I want to contain a navigation controller. in the navcontroller the first/root view will be a custom uiview containing a uitableview that when you touch a cell will push another custom uiview in to disclose details about the touched cell.
I have found the documentation on doing this but it is not making sense to me or seems to be flying over my head. The docs say that you have to create the uiviewcontroller located in the navcontroller views or at least refer to them programatically. I have been using Interface builder and have become quite comfortable using it, so doing it programatically scares me a bit.
Also, This piece of code from the documentation seems troubling:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
[window addSubview:myNavigationController.view];
}
above taken from "ViewController Programming for iPhoneOS" apple documentation
wouldn't this load up and display the UINavigationView immediately?
one problem is I dont want to display the navView immediately. the navController/stack is a secondary tab. So how and where do I impliment my navController(right now I have it instaciated in my delegate(which I think is correct)? I've been able to load up a basic UInavigationController with a navigation bar and a blank view, --minus the custom content view, through interface builder but I'm at a loss as to how to populate the custom content views.
Hope this makes sense.
Any help would be appreciated,
Nick
The first thing to understand is how UINavigationController works. It pushes UIViewControllers, not views. So, when something happens in your second tab (where the UINavigationController lives) you will push a UIViewController onto the stack.
This is typically done in:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
Which is part of the UITableViewDelegate Protocol.
So, when tableView:didSelectRowAtIndexPath is called, you need to figure out which UIViewController to push onto the stack. You can either load this View Controller from a nib, or create it programatically. Since you feel comfortable with IB, I would suggest loading it from a nib.
I would not worry about trivia like "where should I instantiate my UINavigationController?" right now. First, get it working. Then worry about where things "should" go.
It might be best to get the UINavigationController stuff working in a separate project, then fold it into your main project. This lets you ignore lots of little details while you focus on the Navigation Controller.
Related
I have implemented Facebook type left Slide Bar layout in my first view of iphone app. Now, I want to implement this throughout all view controllers (screens) in application, means irrespective of the view the left slide bar should appear on clicking the menu button at the top in all views.
My app contains 25-30 viewcontrollers and my slide bar layout should appear in all views..
Can anyone suggest, how can I include above FB Layout in all views
Thanks in advance
Ramu
Simple, The one view controller in which you have implemented the FB layout and is working. Make it the base class on top of UIViewController. And as for the rest of all the ViewControllers, inherit them from the MasterClass that you just created. Doing this will make the swipe gesture that brings forth the slide bar available to all of your 30 view controllers.
EDIT
Lets see, we have UIViewController, now first of all you create a UIViewController's subclass: say FBViewController ..In this FBViewController you implement the FBLayout such that the swipe and all is working ..on it ..test your app first using only this FBViewController as rootViewController and check all the functionalities.Once everything is working fine, grow on it. What I mean is this.
Say you are creating a Tabbed application, where all the three tabs are supposed to have the same FBLayout style. Then do these steps.
Create FBViewController, it inherits from UIViewController (using UIViewController subclass template, also check the generate XIB button) also have an XIB for it FBViewController.XIB (fully implement FBLayout in it. This will be your base class)
Then Create three more ViewController classes (FirstViewController, SecondViewController, ThirdViewController) again from the UIViewController subclass template, but for these three dont check the generate XIB button. these three will use the XIB of the base class FBViewController (If you are wondering how, then go to step 3 :))
Go to header file of FirstViewController class you created, there you can see #interface FirstViewController: UIViewController replace it with #interface FirstViewController: FBViewController, but before it import FBViewController.h to the header file. Repeat the same for the Other two classes- SecondViewController, ThirdViewController. Since these three will inherit from FBViewController. In their viewDidLoad [super viewDidLoad] will load FBViewController and generate the view. after [super viewDidLoad]; line you can implement ur own methods.
In the three classes just change the initWithNibName method to change the tab bar name and title.
In appDelegate go to didFinishLaunching method and put these three view controller in a tabBarController, set the tabBarController as rootViewController.
And we are done. If your FBViewController is working fine. You will see that all the three classes behave the same way. Thanx to the power of Inheritance.
Cheers, play a bit, have fun.
I had the same problem. I was using a facebook-style menu, and needed it in all view controllers.
You can use a Container Controller. A Container Controller can have the base layout, which I defined in a nib, containing a navigation bar and a bar button item to toggle the menu, and then add child view controllers and remove them as you need them. That way, you can throw whatever view controller you need to the container controller and it will display it.
You can also add gesture control to slide open/close the menu easily.
You will have to make the Container controller your self, it is not standard. I think it is better solution than inheritance, since if you use inheritance you can't make a for example UITableViewController, all your controllers will be of the type of yuor master class. Of course, you can fix this anyway with delegates.
It may sound a bit tricky, but see this tutorial which I used: http://www.cocoanetics.com/2012/04/containing-viewcontrollers/
It wasn't accutally that hard.
EDIT: You can just use a UINavigationController as well. Just set the base view controller to the view controller you want to display, and you can prevent it adding the back button etc to the nav bar by overriding the default methods. Make a UINavigationController as rootNavigationController. Might be simpler.
I'd highly recommend using an open source solution that handles all the edge cases for you - it's both the easiest, most robust and most maintainable (since the community will keep it up to date fro you). ViewDeck seems to be the most popular solution though I have also had success with PPRevealSideViewController. They both provide a very robust implementation that would take a long time to do yourself (e.g. you can optionally enable swipe on the navigation bar or even content area to open the menu). Furthermore they separate the sliding logic and the revealed menu (which can be any view controller you like, but most likely a table view controller) out of your other view controllers. That way any viewcontroller can have a side menu without duplicating any code - separation of concern is great :)
You can make a SharedInstance for SideView class. I am doing same thing for iAD to show throught-out the application.
Please see the the link of iAdSuite ,In which the BannerViewController is SharedInstance so they are easily used for all View Controller
http://developer.apple.com/library/ios/#samplecode/iAdSuite/Listings/TabbedBanner_TabbedBanner_BannerViewController_m.html
So I pretty much built my first app(single view) but i've now decided I should add a little "about/info" button and just give a tiny amount of information on how to use the app and a website to go to.
I wasn't sure about the best way to go about this but storyboards seemed really convenient. A user here answered my question about adding a storyboard to my existing project which seems to work.
Now one question is can I use my current viewcontroller h and m files for the second view (the about screen). I suppose it would technically work if I set the Viewcontroller to the same one as my primary app view.
the only thing this second view is going to have is text and a button to go back. Is it OK to set the connections in the storyboard and just let them use the same Viewcontroller files or is this a big no-no?
Thanks
It is recommended you use a different view controller for each view. In case of a static view controller in which the user doesn't interact with the view except maybe for navigation (which can be handled in the storyboard in many cases), I would just leave that view controller as a generic UIViewController, not a subclass.
Yes you can use the same view controller to control more than one view, however, from what I understand, that doesn't seem like good practice in your case
For instance, if you had similar views with almost identical outlets (say the views have the same UI widgets such as buttons, titles but their layouts vary significantly) you co[uld create a separate view for each different layout and use a single view controller. But from what I understand, in your case, those two views will have different outlets (buttons, labels, etc.)
For this reason, I'd suggest creating a new view controller. Then when you want to show this second view, you will have to present it from your active view controller. I'd highly recommend you read tutorials on view controllers in Apple developer resources. But very quickly, I'd suggest the following
UIViewController *vc2 = [[UIViewController alloc] initWithNibName:#"View2" bundle:[NSBundle mainBundle]]
[self presentViewController:vc2 animated:YES completion:nil];
And to go back to your main view, you'll have to dismiss this second view controller
[self dismissViewControllerAnimated:YES completion:nil];
Of course, they don't have to be animated, you can set them to NO.
After looking for many hours to find a working view switching code, I finally found a great tutorial on YouTube. It was exactly what I needed as I needed to switch views when buttons are pressed.
I just wonder if the techniques used in that video are valid. The used code to switch screens is
viewsViewController *second = [[viewsViewController alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:second animated:YES];
Where viewsViewController (or any class that is used there) is a class that's a subclass of UIViewController. This class is made by clicking File > New File > Add UIViewController subclass.
Is this method according to the Apple guidelines? Is this method memory friendly?
I sure hope the technique is valid. All other examples contained too little information so I couldn't make the example to work. And this is very stylish and short code which works .
That's one way to do it. When you present a view controller modally, there's some expectation that the view controller will go away at some point and the user will return to the parent view controller.
Another option is to employ a UINavigationController, to which you can send -pushViewController:animated: messages.
Yet another way is to let a UITabBarController switch view controllers for you when the user hits the corresponding tab.
One more: you can set the window's rootViewController property, at which point the window will add the view controller's view as a subview of itself.
Your best bet is to read through the View Controller Programming Guide for iOS.
This is one way of doing it. Be aware of some issues. Both views will be in memory, which is okay if they are a reasonable size. The modal view animates above the parent.
There are other models that you can use for simple navigation, if that's your main goal. I would suggest looking at UINavigationController and see if that might better meet your needs. It is probably the most common method to navigate views and provided a lot of the foundation of view management saving you that effort.
Since I am a newbie in iPhone development, I need some advice on how to structure my xib file in order to get the following (essentially, it should be very similar to Google Places app).
I need a NavigationController with:
Map with search functionality.
TableView with search functionality (ideally, the search should be shared between map and TableView).
One view to show details of a selected item, whatever the source view is (map or table).
Map view should have a button to show listing view, and viceversa.
My doubt is, what do I have to nest where? I have a NavigationController with its View Controller set to another class with its own xib, but I don't know how to go on.
Should I create a View with a search bar and another SubView to switch between Map and Table? Or is it better to have two full views each one with its own search bar?
EDIT 1
Finally I have decided to implement the following structure:
- TabBarController
- LugaresNavController (UINavigationController)
- LugaresViewController (UIViewController)
- UISearch
- SubView (UIView)
- MapViewController (UIViewController)
- TableViewController (UITableViewController)
MapViewController and TableViewController have their own xib files. What I want is to have the ability to switch between them into SubView, but I am not able to do it.
I have assigned MapViewController and TableViewController file's owner to their respective class in the xib files, and also have specified which xib to load at the attributes of their representation in the xib corresponding to LugaresViewController, which is their parent.
When I run the application, all I can see is the TabBar with the NavBar and the UISearch. The frame where SubView should render either the map or the table is showing blank...
What am I doing wrong here?
Your fundamental problem is that you are getting your different parent-child hierarchies confused.
To recap: MVC is Model, View and Controller.
iOS has TWO different parent-child hierarchies: One for the controllers and one for the views.
The following are part of the controller parent-child hierarchy:
- TabBarController
- LugaresNavController (UINavigationController)
- LugaresViewController (UIViewController)
This means that LugaresViewController.parentViewController should be LugaresNavController and so on.
However the following doesn't make any sense:
- SubView (UIView)
- MapViewController (UIViewController)
- TableViewController (UITableViewController)
Views can have subviews but views can't have subviewcontrollers,
Are you doing the following?
- SubView (UIView)
- MapViewController.view (UIViewController s view is a subview of Subview)
- TableViewController.view (UITableViewController s view is a subview of Subview)
This is a view parent-child hierarchy. This means that:
SubView has two subviews (MapViewController.view and TableViewController.view)
MapViewController.parentViewController is nil.
MapViewController.navigationController is nil.
you can use view transtions to switch between MapViewController.view & TableViewController.view but not viewController transitions (such as presentModal... or push or pop ViewController...).
If this is what you want, then you just have to make sure that you do:
[SubView addSubview: MapViewController.view];
[SubView addSubview: TableViewController.view];
Incidentally, SubView is a terrible name. Usually we call those containerView or something like that.
subview is such an important concept you want to be able to diffrentiate the concept of a subview from the instance of that view. It's like naming your child "Kid" or your dog "Puppy".
your App is similar to mine, what I've done:
- TabBarController
- TableView
- SearchBar
- DetailButton ----\
- MapView \____ push ModalViewController
- SearchBar /
- DetailButton ----/
now if someone pushes a button in the table view or map view I'm opening the same View but pass other information to initialize it. btw. what is a LugaresViewController?
First try only adding a TableView and a MapView in each tab and look if the nib-binding works well. If not, you're missing something, load nib named or class type. Afterwards you can add the SearchBarController's and provide functionality for that.
First of all, I can't really say I agree with your tabbar application. I think a navigation application might work better for this idea. The first view would then have the navigationbar automatically added, with below the UISearchbar, a window, and a normal tabbar.
The UIWindow should contain a subview. That would be either the table, or the map. When you first load the application, and show, say, the table, you'd do:
[window addSubview:tableViewController];
When you switch to the mapview, you'd do something like:
[tableViewController removeFromSuperview];
[window addSubview:mapViewController];
So, for switching views, that's where the UITabBar comes into play. Make sure the tabbar has two segments. Hook up an IBAction to that, which looks a bit like:
-(IBAction)segmentedControlIndexChanged {
switch (segmentedControl.selectedSegmentIndex} {
case 0:
<call function for removing mapview and adding tableview>
case 1:
<call function for removing tableview and adding mapview>
default:
break;
}
}
Last but definately not least, which might be the answer to your edit: make sure you've connected all the connectors in Interface Builder (or, if your using XCode 4, just the .xib-file), from the .xib to the File Owner's.
EDIT: Ofcourse, the detail-view for the items pressed on the table/map is pushed in the navigationItem, so the back-button is automatically created and functional in your detailview.
Good luck!
I have always sort of wondered when to use a UIView vs. a UIViewController on the iPhone.
I understand that you shouldn't use a UIViewController unless it's a full-screen view, but what other guidelines are there?
For example, I want to build a modal overlay - a screen that will slide into place over the current screen. If this modal overlay is full-screen, should it be a UIViewController? The last time I built something like this, I subclassed UIViewController, but now I wonder if that was correct.
From Apple's View Controller Programming Guide for iOS:
"The most important role of a view controller is to manage a hierarchy of views. Every view controller has a single root view that encloses all of the view controller’s content. To that root view, you add the views you need to display your content."
Also:
"There are two types of view controllers:
Content view controllers manage a discrete piece of your app’s content and are the main type of view controller that you create.
Container view controllers collect information from other view controllers (known as child view controllers) and present it in a way that facilitates navigation or presents the content of those view controllers differently.
Most apps are a mixture of both types of view controllers."
This is a great question.
My basic rule of thumb. Is that every major 'page' of an application gets it's own view controller. What I mean by that is that during the wire framing stage of application design, everything that exists as its own entity will eventually be managed by its own View Controller. If there is a modal screen that slides over an existing screen, I will consider that to be a separate 'page' and give it its own view controller. If there is a view that overlays and existing page (such as a loading screen or help popup.) I would treat those differently, implement them as UIView subclasses and keep the logic in that 'pages' view controller. It the popup has behavior I will communicate back to that pages View Controller using the delegate pattern.
I hope this helps. It is very much a philosophical and architectural question and much could be written about it.
I use UIViewController whenever a view is full screen and either has outlets/actions and/or subviews.
Put everything on a screen into a UIViewController until the view controller starts to have too much code, then break out the screen into multiple UIViewControllers contained by one master view controller...
To put that into context of your answer, make a view controller for that modal overlay. It will have one anyway if you are using a nav controller to present it (and you probably should).
I have a somewhat different approach:
Override UIView if you plan to do custom drawing in drawRect. Otherwise, subclass UIViewController and use [self.view addSubview: blah] to add the components of the page.
There are a few other special cases, but that handles about 95% of the situations.
(You still will often need a UIViewController with a custom UIView. But it's common to have a custom UIViewController with no corresponding custom UIView.)
Is the thing that slides in a self contained screen? I mean, does it directly interact with the parent? If so, make it a UIView, if not, probably recommend a UIViewController.
A UIView is part of the UIViewController see the view property of UIViewController for this. As you pointed out correctly UIViewController manages a complete screen and there should be only one visible UIViewController at a time. But in most cases you will have more UIViews or subclasses of UIView visible on the screen.
The example you gave would be a correct use in most cases. As you may have noticed you will get a lot of functionality when subclassing the UIViewController. Animating the appearance and dismissal of the UIViewController would be one of them.
As marcc pointed out if the thing you want to slide in is not a self contained screen you would be better off using a UIView.
As a conclusion I would say that if you want to use the functionality that comes with subclassing UIViewController than go for it make it a UIViewController. Otherwise a UIView might be better.
The itunes U Standford class has a great lecture on UIViewControllers I would recommend watching it, because it has a lot of information regarding UIViewControllers in general.
If you are familiar with the MVC pattern, then you should be able to understand the difference between UIVIew and UIViewController. To make a simple statement, UIView is for rendering UI elements on screen. UIView is the superclass of pretty much all Cocoa Touch UI elements. Those elements do not know what information they are supposed to display, what they should do when a user clicks a button, what happens when an async network request is completed and so on. UIViewController is for all that and more. The view controller is responsible for placing the UI elements in the correct locations on screen, setting the contents of the UI elements, handling button presses and other user inputs, updating the model when needed etc.
Conceptually, a single UIViewController controls the contents of the whole screen in an iPhone App and that is why it is often easy to think of things in terms of view controllers. If you need a view where the user can select ingredients for a food recipe, you'll need a UIViewController for that. I made this distinction for myself because coming from a Java background I wasn't used to the framework enforcing MVC. I would think of things in terms of UIViews, and start implementing them that way and then run into all sorts of trouble because of that. If you are going to stick to UIKit for your App, then the workflow Apple has made for you is: for each separate view in your App, create a UIViewController subclass and then use Interface Builder to place the UI elements and to create connections for buttons etc. It works wonders, saves a ton of time and lets you concentrate on making your App function well.
I use UIViewController for showing View on full Screen.
For better control on custom view I prefer subclass of UIViewController instead of UIView, earlier I was using UIView for making custom sub class.