I've had a lot of experience customizing UINavigationBars and find it is a royal pain in the a** to get it to do what I want without a lot of effort. So I've written my own custom UIView that behaves just like a UINavigationBar and is fully and easily customizable. However, I am having a problem, when the Navigation controller pushes a new controller onto the stack, my custom view stops receiving touch events.
To make this more clear, my app loads and displays a view controller, in the viewDidLoad method, I create and add my custom nav bar to the controller's view. A navigation controller is created programmatically and a view controller is pushed to it. At this point my custom view is on top and receiving touch events. When I push another view controller to the navigation controller's stack, my custom view is still on top and visible, but not receiving events.
So my question is how to I get my custom nav bar back into the responder chain?
Thanks for your help!
If you don't have to support iOS < 5.0 you should try to add the UINavigationBar using UINavigationController's - (instancetype)initWithNavigationBarClass:(Class)navigationBarClass toolbarClass:(Class)toolbarClass method instead of doing it manually.
Related
Ok so I have a tabbar iPhone application. The tabbarcontroller contains about 5 view controllers that are each embedded in their own navigation controller with the exception of 1 in which I just added a navigation bar in IB for a consistent look throughout the app. On every navigation bar in the app, I want a rightBarButtonItem that will open up the same modal view controller no matter where it is selected from. Similar to the "Now Playing" button in the music app, I want the button to stay on every navigation bar regardless of which tab I'm on or how deep I navigate into a navigation controller. How would I go about doing something like this? Is there some way I could simply apply the button to every nav bar in the same way UIAppearance can apply an image to every nav bar in an app? Thanks in advance for any ideas.
A simple approach would be to create a base view controller from which all your other view controllers extend.
With this in place, you could set up a UIBarButtonItem in the viewDidLoad method that attaches itself to the navigation bar and listens for events. From there, it would be quite easy to observe events and present either a modal view controller or push the appropriate view controller on to the navigation stack.
I use this approach for a "logout" bar button item that presents the login view controller when tapped as a quick alternative for users to sign out of their account.
The only down side to this is that each and every view controller that inherits from the base view controller will have the logout button in the navigation bar. Should you need other buttons or want to hide the default button, you need to replace it with another button instead.
It's a quick and easy approach and is also quite simple to remove if required as you can just change the header file to reflect the inheritance rather than sifting through several view controllers removing every instance of the button. It's also easy to maintain as you could overload the button target in any subclasses to perform different functionality when the event is fired.
I'm getting confused on view controllers and would love a straight example. Here's the preamble:
I have a UIViewController with a matching .xib.
By default IB gives me a single View in the Document window.
I can make it appear by telling my UIWindow to addSubview:controller.view and bringSubviewToFront:controller.view
Here's the questions:
Should I add another View to the ViewController in IB? Or is there a better, programmatical way?
How do I tell the ViewController to switch between the Views?
From the ViewController downward, what does the code look like to achieve this?
I'm trying things but just making a mess so I thought I'd stop and ask...
Note that every button, label, image, etc. in your main view controller is actually a view in itself, however I've interpreted your question to mean that you want to manage multiple full-screen views or "screens". Each screen should have its own view controller to manage it. So to get the terminology right, a view-controller is an object that manages a single full-screen view (or almost full screen if it's nested inside a navigation controller or tab bar controller for example) and a view is the big area managed by the view controller as well as all the sub-views (images, buttons, labels, etc.) within it (they are all UIView sub-classes). The view controller manages all of them on that screen, if you want another screen/page then you should create a new view controller to manage it.
The root view controller (the one you add to the window) can be a plain old normal view controller that you've designed in IB, however it's probably more useful if you use a navigation controller or a tab bar controller and add your designed view controller to that - then you can push additional view controllers as needed.
Another way (if you don't want navigation or tab-bar style) would be to transition to other view controllers directly in the main window using whatever transitions you like (or just replace the old one). We'll leave that for now though.
Any sub-views of your main view controller (the one you've designed in IB) will be automatically loaded from the nib file, but you can also add your own views programatically if you want (typically you would use one or the other, i.e. nibs or programatically, but you can mix and match if you want). To do it programatically, override loadView in the view controller and then call [super loadView]; then do [self.view addSubView:myOtherView]; (create the myOtherView first of course). Note that the first time .view is accessed on your view controller, it actually calls loadView to create the view, so inside loadView it's important to call [super loadView]; before trying to access self.view :D
To switch between views, using the navigation or tab bar controllers makes it very easy. So put your main view controller inside (for example) a navigation controller and put the navigation controller in the window, so you've got window->navigationController->myController. Then from an action method in your view controller (you can hook up the action methods in IB), for example when an "about" button is pressed do this:
- (void)doAbout
{
// Create the about view controller
AboutViewController* aboutVC = [AboutViewController new];
// Push the view controller onto the navigation stack
[self.navigationController pushViewController:aboutVC animated:YES];
[aboutVC release];
}
Note that the about view controller is created programatically here - if your about view is designed in IB then instead use initWithNibName:bundle: to create it.
And that's how you manage multiple screens.
I have a custom UITabBarController and I want it to slide out the old view and slide in the new view whenever a TabBarItem gets pressed. I looked at UITabBarControllerDelegate but it just offers me to decide if the view gets displayed not how (via shouldSelectViewController).
Is there a way to do that?
(My goal is to have a starfield background that looks almost the same on all the 4 views. It should look like the items get changed and the background just scrolls by a little)
Subclass UITabBarController and make it it's own delegate. Now you can intercept methods like tabBarController:shouldSelectViewController: and manipulate any custom views you have added to the tab bar. And if you add your starfield to the tab bar view, and then use tab controllers that have translucent views the common background can show through.
And you can even intercept tab bar controller methods directly like setSelectedIndex: to have even more control to let you fade things out. But just make sure that you call the super version of the method at some point if you do this so the tab bar remains functional.
I have an app that uses a UINavigationController as its main way of showing data.I want a Settings screen to pop up, but I also want to be able to push new views for Settings. From what I've found, I can't use a UIViewController do to this. How can I present a view by sliding it, and also have content pushed onto it?
You can display the view for your view controller subclass either by presenting it modally (slides from the bottom and takes over the whole screen) or pushing it onto the navigation stack with animation (slides from the right and keeps the navigation bar).
In either case, you control the content of the view using your view controller subclass. Typically you update labels and controls in the viewWillAppear method.
I have been in the process of learning to build iPhone applications for the last two weeks. I've gotten through a fair amount of content, and now I'm trying to create a modal pop up with presentModalView.
I can can successfully create and slide up a view, but I notice that modal views don't provide you with a default navigation bar at the top of the window, which makes sense for flexibility I guess. Most modal views I've seen have a "Cancel" and a "Done" or "Save" button as navigationItems on what looks to be a UINavigationController. My thought then was just to instantiate a navigation controller and push the single view onto the view controller stack, and presentModalView:navController.view ...
Because the view is relatively complex, I was trying to lay out both the UINavigationController, with the bar buttons, and the view I was hoping to push onto the stack in a single xib -- no matter what I try, I can't seem to get the linkages correct. Can you even do this? Or should I create a separate class/xib for the view I'm going to be pushing onto the navigation controller? Seems like a lot of classes and files for one screen, so my feeling is I must be missing something.
At this point, I could have done it programmatically about an hour and a half ago... however, this is a real nag, since IB seems GREAT for some things. Anyone have an experience with a situation like this?
Thanks,
Josh
If you're not going to use this new XIB for navigation, there's no point in making a navigation controller.
In interface builder, simply drag a UINavigationBar to the top of your view, and add a "Done" Button. Now, add an IBAction to the done button to dismiss the view controller. Your ViewController code for the dismiss IBAction should look something like this:
-(IBAction)dismiss {
//Any logic before dismissing the modal view
[super dismissModalViewControllerAnimated:YES];
}