I have a UISearchController which has it's own custom results controller, rather than filtering the contents in the immediate view.
The UISearchBar appears in the navigation bar correctly, but when I begin typing characters into the search box, my custom controller appears, and fills the entire screen, covering up the navigation bar and the window I'm typing my query into.
This used to work, but I recently changed my storyboard to have the UINavigationController as the entry point, leading into a UITabBarController, which then had it's tabbed controllers.
The UITabBarController now has all the logic for the searches, so it can route the actions taken on the search results to the appropriate tab via a protocol I've implemented.
Below is my storyboard, note, that the custom search result controller is the item sitting below the UITabBarController, and the unattached item on the top right corner, is used via a library and is attached to the top tab's controller internally.
I'm starting to wonder if this specific configuration works? Can I have the UINavigationController in front of the UITabBarController?
I wanted to have a persistent search bar up top with all the shared search code in one spot (UITabBarController) rather than put a UINavigationController in front of each tab?
If this should work, are there any ideas why the custom search results controller is now covering the entire screen, instead of going under the navigation bar?
Turns out the issue was I needed to call
definesPresentationContext = true
In the view controller that was already being displayed (tab 1)
When I moved the search code over to the UITabBarController, I moved that with it.
I believe you just need to have
edgesForExtendedLayout = []
Inside your SearchResultsControllers ViewDidLoad()
Should now be under the searchController searchBar.
Related
The incorrect navigation bar is appearing on my Table View Controller screen (see Storyboard Below).
I would like what's displayed on the storyboard to be my navigation bar (i.e. with "Main Feed" title and Sign Out button on the top right). However, this is what I'm actually getting -
There are two issues here: 1) The incorrect navigation bar is displaying (this one has a login back button); 2) the first few table view cells are placed underneath the nav bar vs. under it.
This happened after I embedded the Table View controller in the Tab Bar Controller. I want a bottom tab bar in the main portion of my application hence the reason why I added the Tab Bar Controller. Any suggestions on how to fix this? Rather than using the Tab Bar Controller in storyboard, is there a way to do this programatically? Thanks!
The navigation bar that you are seeing on top of the stack is the navigation bar from the UITabBarController itself, that is why you are seeing the back button show "login". There's a few ways to work around this, programmatically:
When you initialize the UITabBarController, set it's navigationController's navigation bar property to "hidden"
Go through each view controller form the beginning of your app up to where you first see this problem and in the "init" method of the viewController you are testing, set the navigationbar to hidden. Something like, self.navigationController?.navigationBar.hidden = true;
This is how you can "debug" this issue, but it's going to take some tweaking to get it right.
I have an application that has a UITabBarController in a UINavigationController. (The UITabBarController is not the "Initial View Controller" for the story board.)
In the initial UIViewController, I have a UISearchController which allows for content to be searched from a remote source.
This worked fine until I added the UITabBarController. Now, the search bar displays fine in the default state, but once you start typing inside of it, it gets pushed up past the top edge of the view.
I realize this probably has a lot to do with automaticallyAdjustsScrollViewInsets, extendedLayoutIncludesOpaqueBars, and/or edgesForExtendedLayout, but in all my tweaking, I've been unable to find the magic combo to get the UISearchController to not push itself up past the top of the view.
Any ideas on how to make it work?
See these screengrabs from this example project:
Initial view:
Search text box becomes first responder:
After typing a word and hitting enter:
I ran into this issue too, and here's a solution: setting definesPresentationContext = true on UITabBarController instead of the table view controller seems to fix it.
Apparently, you have to go all the way up until navigation controller in container hierarchy. Not the most obvious thing in the world if you ask me.
Although definesPresentationContext worked for me previously, since iOS 10 at some point I had to disable Adjust Scroll View Insets on my search results view controller. More on my answer at UISearchBar gets cut off when using a UINavigationController inside a UITabBarController
I'm trying to create a tabbed application with navigation elements inside the tab bar, as seen in the picture below (the red bar) using Swift/XCode 6.2. Basically those three icons in the middle will direct the user to different view controllers. The other two icons would be context-based. For example, on a table view page you would see the menu icon and add new icon as seen in the image. However, clicking on a row would change the menu icon to a back icon, and the add icon to something else.
That's the general idea, but I'm having a very hard time implementing something even close to this. The first issue is that whenever I embed a view in a Tab Bar Controller, I can't move the tab bar to the top. However, when I create a custom UITabView in a View Controller, Control + Click and dragging a Tab Bar Item to another view doesn't create a segue. I haven't even begun to tackle having the navigation elements inside the bar.
I guess what I'm asking is just for a little guidance on what route to take to tackle this. I'm assuming I can't use a Tab Bar Controller or Navigation Controller because it doesn't seem like I can customize them all that much. So custom Tab Bar and Navigation Bars, and then implemnt the segues and button changes programmatically?
Thanks.
I will try to guide you from an architectural perspective (so you won't find much code below).
Using a UITabBarController
In order to achieve what you are suggesting, you are right you cannot use a UITabBarController straight away, among several reasons, the most immediate one is that they are meant to be always at the bottom and you want it in top (check Apple's docs). The good news is that probably you don't need it!
Note: If you still want to go with a UITabBarController for whatever reason, please see #Matt's answer.
Using a UINavigationController
You can use a UINavigationController to solve this task, since the UINavigationBar of a UINavigationController can be customized. There are multiple ways on how you can organize your view's hierarchy to achieve what you propose, but let me elaborate one option:
To customize a UINavigationBar's to add buttons, you just need to set its navigationItem's title view:
// Assuming viewWithTopButtons is a view containing the 3 top buttons
self.navigationItem.titleView = viewWithTopButtons
To add the burger menu functionality on a UINavigationController you can find several posts on how to do it and infinite frameworks you can use. Check this other SO Question for a more detailed answer (e.g. MMDrawerController, ECSlidingViewController to mention a couple).
About organizing your view hierarchy, it really depends on if when the user taps one of the main top buttons, it will always go to the first view controller in the new section or if you want to bring him back to the last view in the section where he was.
3.1 Switching sections displays the first view of the new section
Your app's UIWindow will have a single UINavigationController on top of the hierarchy. Then each of the 3 top buttons, when tapped, will change the root view controller of the UINavigationController.
Then, when the user changes section, the current navigation hierarchy is discarded by setting the new section view controller as the UINavigationController root view controller.
self.navigationController = [sectionFirstViewController]
3.2 Switching sections displays the last displayed view in the new section
This will require a slightly modified version of the above, where your each of your sections will have its own UINavigationController, so you can always keep a navigation hierarchy per section.
Then, when the user taps one of the top buttons to switch section, instead of changing as previously described, you will change the UIWindowroot view controller to the new section's UINavigationController.
window.rootViewController = sectionNavigationController
Using a custom implementation
Of course, the last and also very valid option would be that you implement yourself your own component to achieve your requirements. This is probably the option requiring the biggest effort in exchange of the highest customizability.
Choosing this option is definitely not recommend to less experienced developers.
I'd like to take a stab at this--I think it is possible to use a tab bar controller here.
Your topmost-level view controller will be a UITabBarController with a hidden UITabBar.
Each tab is contained in a UINavigationController.
All view controllers in the navigation controller will be a subclass of a view controller (say, SwitchableViewController).
In SwitchableViewController's viewDidLoad, you set the navigation item's title view (i.e. whatever's at the center; self.navigationItem.titleView) to be the view that holds the three center buttons. Could be a UISegmentedControl, or a custom view.
Whenever you tap on any of the buttons, you change the topmost UITabBarController's selected index to the view controller you want to show.
Issues you may encounter:
Table views inside tabs will have a scrollIndicatorOffset at the bottom even if the tab bar is hidden.
Solution: Play around with the automaticallyAdjustsScrollViewInsets of the tab bar controller, or the inner view controller. https://stackoverflow.com/a/29264073/855680
Your title view will be animated every time you push a new view controller in the navigation stack.
Solution: Take a look at creating a custom transition animation for the UINavigationController.
I want to add UITabBarController as root view of my UINavigation controller. The purpose of that is that I want to make similar navigation as Facebook app: Then user select contact on Contacts tab - pushed view with user details doesn't have TabBar.
So, I have navigation controller, tab bar as a root view or it and couple TableViewControllers inside this UITabBarController.
I have two major issues with that:
I can't assign title for navigation bar for root views of tabbar. If I open contact details I have navigation bar title and no tab bar (as I wanted). But if I select Contacts or Favorites - those views have empty navigation bar title. I've tried to set it on viewDidLoad and viewDidApper without any success
Even worse issue. When I press Favorites table view insets are broken. first cell is under navigation bar. First loaded tableview (in my case Contact) displayed correctly. Adjust scroll view insets is YES for both TableViews.
Update:
Solution storyboard (note property "Hide Bottom Bar on the Push" is switched to YES).
I was also struggling with UITabBarController + UINavigationController issue. When UITabBarController was contained by UINavigationController, content insets were acting really weird.
I would suggest to use navigation controllers inside UITabBarController and when next controller is pushed, set 'hidesBottomBarWhenPushed' on that controller to YES.
This would also solve setting navigation bar title, as navigation controller is closer to view controller. You can just use self.navigationItem.
If you leave it to current setup - UITabController contained within UINavigationController, then you need to modify navigationItem on controllers tabBarController (self.tabBarController.navigationItem). Note that best place for it would be in view controllers 'viewWillAppear' for every controller contained within UITabBarController, as they share one navigation item.
I have an application with 5 UIViewControllers each inside a corresponding UINavigationController, all tucked inside a UITabBarController that displays 5 tabs at the bottom of the screen.
I want to display another UIViewController (inside a UINavigationController) when a dialog button is pressed.
This view should only be loaded and unloaded programatically; i.e. it should not appear in the tab bar. However, I want the tab bar to be visible always.
If I add the [UINavigationController view] to [self window] the UITabBar is covered. If I add it to any other layer, the UINavigationController adds on the compensation it has for the status bar so appears further down than expected.
A solution would be to have the 6th UINavigationController added to the UITabBar with the others, but with its tabBarItem hidden. Then I can show it and hide it using the tabBars selectedIndex property.
Accessing the tabBarItem through the UIViewController shows no obvious way of doing this.
#wisequark, I think you completely misunderstood and you have almost rewritten the architecture of my application. However I have a separate navigation controller for each view as they are mutually exclusive and there is no concept of "drilling down".
#Kendall, This is what I expect I will have to do - have the modal view appear with a hide button to bring back the normal interface. But it would be nice to keep the tab bar always visible, so I was just wondering if anyone knew of a way.
It sounds as though you have a mess on your hands. A UINavigationController is a distinct object that is very different from a UITabBarController. In general, your application should have a tab controller, one of who's tab's loads a UINavigationController which in turn loads it's views - not that both maintain management over the different views. It is also improper to refer to the display of a UIViewController as such an object doesn't have a visual representation. In the case of a UINavigationController, the navigation controller object is responsible for displaying a navigation bar and a table view (in the most common case) and for managing the display of all the views in the navigation hierarchy. It itself has no corresponding representation on screen. Similarly, a UITabBarController presents a tab bar and is responsible for the loading and unloading of the views and/or view controllers attached to the tab buttons. If we were to present this as an image, it would look something like this -
alt text http://img.skitch.com/20081112-2sqp7q4wafa34te1ga337u4k8.png
Well, it sounds like what you really want to do is present a modal view with the tab bar still visible. You could add your view as a subview of the tab bar controller's view. The tab bar's view is, oddly enough, not the tab bar itself but rather a view containing the tab bar and the selected item's view.
Alternatively, you could try calling presentModalViewController:animated: with the selected tab (i.e. [tabBarController.selectedViewController presentModalViewController:animated:]) as the receiver instead of the tab bar. I seem to recall doing this once (quite by accident) and the tab bar remained visible.
One more thought: since each of your five view controllers is a UINavigationController, you could always pushViewController:animated: onto the selected view controller, then hide the back button. Your view will just appear without animation. But you'll need to remember to pop your view controller off the stack whenever the user switches to another tab. That might take a bit more work.
The best idea I could think of would be to either push a modal navigation controller for your view (which would hide the tab bar which you do not want), or to get the tab bar controller current selected view controller (really your navigation controller for a tab) and push your new view controller on there - and then pop that view when another tab is selected with a tab bar delegate.
It seems wierd to me to push the view onto random tabs though, if the view is created from a dialog that is modal, I don't see why the view itself should not also be modal and hide tabs.