I'm looking to create similar functionality to Apple's maps application in Swift. Is there anyway to integrate a UISearchController in to a regular view (i.e.: not a UITableView). Dropping one in through Storyboard results in a crash after clicking inside the connected searchbar. Or is there some way I can achieve this outcome with a UITableView?
If you want to use UISearchController with a non UITableView, here is how I did it.
Since the UISearchController is not (yet!) supported by IB, you do not need to add anything in it, like a UISearchBar.
#interface UIViewControllerSubclass () <UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate, UISearchControllerDelegate, UISearchResultsUpdating>
#property (strong, nonatomic) UISearchController *searchController;
#end
#implementation UIViewControllerSubclass
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any custom init from here...
// Create a UITableViewController to present search results since the actual view controller is not a subclass of UITableViewController in this case
UITableViewController *searchResultsController = [[UITableViewController alloc] init];
// Init UISearchController with the search results controller
self.searchController = [[UISearchController alloc] initWithSearchResultsController:searchResultsController];
// Link the search controller
self.searchController.searchResultsUpdater = self;
// This is obviously needed because the search bar will be contained in the navigation bar
self.searchController.hidesNavigationBarDuringPresentation = NO;
// Required (?) to set place a search bar in a navigation bar
self.searchController.searchBar.searchBarStyle = UISearchBarStyleMinimal;
// This is where you set the search bar in the navigation bar, instead of using table view's header ...
self.navigationItem.titleView = self.searchController.searchBar;
// To ensure search results controller is presented in the current view controller
self.definesPresentationContext = YES;
// Setting delegates and other stuff
searchResultsController.tableView.dataSource = self;
searchResultsController.tableView.delegate = self;
self.searchController.delegate = self;
self.searchController.dimsBackgroundDuringPresentation = NO;
self.searchController.searchBar.delegate = self;
}
#end
I hope it is enough to work :-)
Then of course you need at least to implement UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdater methods.
Enjoy!
Trying to figure out UISearchController myself. Setting it to the titleView is convenient, but on one of my pages, I had to put the searchBar near the top of the UIViewController:
// Add a normal View into the Storyboard.
// Set constraints:
// - height: 44
// - leading and trailing so that it spans the width of the page
// - vertical position can be anywhere based on your requirements, like near the top
#IBOutlet weak var searchContainerView: UIView!
var searchResultsController = UISearchController()
override func viewDidLoad() {
// TODO: set the searchResultsController to something
let controller = UISearchController(searchResultsController: nil)
// have the search bar span the width of the screen
controller.searchBar.sizeToFit()
// add search bar to empty View
searchContainerView.addSubview(controller.searchBar)
searchResultsController = controller
}
UPDATE:
After implementing UISearchController in a project or two, I found myself gravitating toward #adauguet's approach of embedding the search bar into the Navigation Bar.
Here's the code in Swift. One difference though is that it doesn't set the searchBar delegate, since searchResultsUpdater already listens for text changes.
override func viewDidLoad() {
super.viewDidLoad()
// locationManager.delegate = self
// locationManager.desiredAccuracy = kCLLocationAccuracyBest
// locationManager.requestWhenInUseAuthorization()
// locationManager.requestLocation()
let locationSearchTable = storyboard!.instantiateViewControllerWithIdentifier("LocationSearchTable") as! LocationSearchTable
resultSearchController = UISearchController(searchResultsController: locationSearchTable)
resultSearchController?.searchResultsUpdater = locationSearchTable
let searchBar = resultSearchController!.searchBar
searchBar.sizeToFit()
searchBar.placeholder = "Search for places"
navigationItem.titleView = resultSearchController?.searchBar
resultSearchController?.hidesNavigationBarDuringPresentation = false
resultSearchController?.dimsBackgroundDuringPresentation = true
definesPresentationContext = true
}
Also, I wrote a blog post that creates a project from scratch that uses UISearchController to display map search results. It also does other things that you might want in a map project, like get the user location, drop pins, parse placemarks into a one-line address, and create callout buttons that take you to Apple Maps for driving directions.
http://www.thorntech.com/2016/01/how-to-search-for-location-using-apples-mapkit/
The blog post is quite long, so here's the associated git repo if you just want to skip to the code:
https://github.com/ThornTechPublic/MapKitTutorial
I added a Search Bar and Search Display Controller in my View Controller in the storyboard. The view controller contains only the search bar and search display controller and does not have it's own TableView. When you add the search bar in your view controller, it sets your view controller as it's delegate automatically.
Now the Search Bar and Search Display Controller has a table view of itself which it uses to display the search results when you click inside the box and start typing. This table view expects your view controller to provide the implementations of the numberOfRowsInSection and cellForRowAtIndexPath functions for it to display the data properly.
When you run your project without these and tap inside the search bar, you will get the following error:-
tableView:numberOfRowsInSection:]: unrecognized selector sent to instance 0x7fbf63449660
*** Terminating app due to uncaught exception 'NSInvalidArgumentException'
If you see, the error is at the numberOfRowsInSection method.
Change your view controller definition from
class ViewController: UIViewController
to
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource
and implement the required methods which are:-
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
return UITableViewCell()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 0
}
I have just added default return values in the above methods.
Now if you filter out your data source in your searchviewdelegate methods and set up your number of rows and cell info in the above two methods properly, it should work.
Hope this helps!
I had some trouble converting from SearchDisplayController in UIViewController to SearchController in ViewController because SearchController implementation isn't so intuitive. But you can just add in searcher from SearchController itself into any view. You cannot set constraint though because the search bar would move up when you focus/select it (if you know how to set the constraint to seachController.searchbar after adding it to any view, LET ME KNOW!). Below I am sharing a checklist that I found very important/valuable when implementing SearchController in ViewController.
//you can just add searcher to any view. It would automatically move up to show the tableView like magic. But for this reason, you cannot set constraint to the search bar to the placeholder view that you are adding it to.
[self.searchBarPlaceHolderView addSubview:self.searchController.searchBar];
//you need this to prevent search bar to drop down when you focus/select it. You would want to set this to NO if you are adding searchBar to the navigation bar's titleview.
self.searchController.hidesNavigationBarDuringPresentation = YES;
//make sure you set this in your viewController
self.extendedLayoutIncludesOpaqueBars = true;
self.definesPresentationContext = YES;
// you also need to give the search controller a tableViewController that can be displayed. You can also do just self.searchResultsController = [[UITableView alloc] init] for a generic one.
self.searchResultsController = (UITableViewController *)[ [UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"searchResultsTableViewController"];
self.searchResultsController.tableView.dataSource = self;
self.searchResultsController.tableView.delegate = self;
self.searchResultsController.definesPresentationContext = NO;
self.searchController = [[UISearchController alloc] initWithSearchResultsController:self.searchResultsController];
Related
When setting a UISearchController search bar in the navigationItem titleView, the search bar can't be edited.
In my viewDidLoad I am configuring a UISearchController.
self.searchViewController = [self.storyboard instantiateViewControllerWithIdentifier:NSStringFromClass([SearchViewController class])];
self.searchViewController.delegate = self;
self.searchController = [[UISearchController alloc] initWithSearchResultsController:self.searchViewController];
self.searchController.delegate = self;
self.searchController.searchResultsUpdater = self;
self.searchController.searchBar.delegate = self;
self.navigationItem.titleView = self.searchController.searchBar;
I can't tap the search bar. The cursor does not appear and there is no user interaction.
Oddly, if I initialize the UISearchController locally without setting it to a property, then I can edit the search bar, just no delegate callbacks.
self.searchViewController = [self.storyboard instantiateViewControllerWithIdentifier:NSStringFromClass([SearchViewController class])];
self.searchViewController.delegate = self;
UISearchController *searchController = [[UISearchController alloc] initWithSearchResultsController:self.searchViewController];
searchController.delegate = self;
searchController.searchResultsUpdater = self;
searchController.searchBar.delegate = self;
self.navigationItem.titleView = searchController.searchBar;
Another interesting behavior is that the clear button works (if some text is set in the search bar while initializing).
I had the same issue.
Imagine you have FirstViewController and SecondViewController, and booth have a UISearchBar on the titleView.
To fix the problem I had this code to booth UIViewController's.
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.definesPresentationContext = true
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
self.definesPresentationContext = false
}
I am setting self.definesPresentationContext = YES; in the view controller that presents the view controller in question.
This must be set to self.definesPresentationContext = NO; in viewWillAppear:.
Now the search bar in the presented view controller can be edited.
Set your search bar to navigation title view :
self.navigationItem.titleView = self.searchBarTop;
then just set this view either left/right button of Navigation Bar
UIBarButtonItem *searchBarItem = [[UIBarButtonItem alloc] initWithCustomView:searchBar];
self.navigationItem.rightBarButtonItem = searchBarItem;
I hope this will work for You!!
I have just solved a very similar problem in my app, and thought I'd share the solution in case the existing solutions don't fix it for you.
In my case I had a tab bar application, with my custom controllers in the tabs, embedded in the navigation controllers. The symptoms were exactly the same, the search bar showed in the title area of the navigation bar, but was not interactive.
I have discovered that the problem was that I used my custom subclass of the UITabBarController and I have overriden the viewWillAppear(animated:) method, but forgot to call super.viewWillAppear(animated:) in the implementation. The additional symptom was that when I switched the tabs, the search bar suddenly became interactive and everything worked fine, just the interaction on the initial tab was disabled.
I hope this helps someone.
In your first block of code, you're instantiating with a SearchViewController identifier. In the second, you're using HBSearchViewController. This suggests that there might be another difference in your code besides using / not using an outlet.
In my app, I need to create a Search Suggestions interface -- very similar to Google search (it starts displaying suggestions as you type in the search field).
I did it with a UISearchController with the search bar in navigation bar, set it up like this:
// setup search controller
searchController = UISearchController(searchResultsController: searchSuggestionsController)
self.searchController.searchResultsUpdater = searchSuggestionsController
self.searchController.hidesNavigationBarDuringPresentation = false
self.navigationItem.titleView = self.searchController.searchBar
// ISSUE!! definesPresentationContext needs to be false or I can't push this
// controller multiple times on the navigation stack
self.definesPresentationContext = true
while it works fine when search controller is pushed to the navigation stack the first time, it doesn't let the search bar get the focus when it is pushed the second time, as shown below
but if I set it to false: as soon as I start typing into the search bar, the navigation bar (along with the search bar) disappears. This is expected behavior since (because of definesPresentationContext = false) UISearchController is now trying to display its view on top of UINavigationController's view, as shown below:
Is there a way to achieve this through UISearchController? If not, any pointers on how should I create a custom control for this? (Code for the minimal app shown in the animations can be downloaded here)
It's not possible to use UISearchController like this. UISearchBar and UINavigationBar are known to not play well together. What I decided to do was, every time user taps the Search button, I check childViewControllers array of my navigation controller and if I find an instance of SearchViewController in there, I pop back to it. Otherwise I push it.
// This function lives inside a UINavigationController subclass and is called whenever I need to display the search controller
func search() {
if let _ = self.topViewController as? SearchViewController {
return
}
var existingSearchController: SearchViewController? = nil
for childController in self.childViewControllers {
if let searchController = childController as? SearchViewController {
existingSearchController = searchController
}
}
if let searchController = existingSearchController {
self.popToViewController(searchController, animated: true)
return
}
self.performSegueWithIdentifier(StoryboardConstants.SegueShowSearchController, sender: nil)
}
The proper fix would have been, of course, a custom control but we did not have the time to write something custom at this stage.
I have the following code in my app, specifically in viewDidLoad: that sets up my UISearchController.
self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.searchController.searchResultsUpdater = self;
self.searchController.hidesNavigationBarDuringPresentation = NO;
self.searchController.dimsBackgroundDuringPresentation = NO;
self.definesPresentationContext = NO;
self.searchController.searchBar.scopeButtonTitles = #[];
self.searchController.searchBar.searchBarStyle = UISearchBarStyleProminent;
[_tableView setTableHeaderView:_searchController.searchBar];
Whenever the search bar (which is added to the tableView) is invoked, the UIStatusBar color changes from UIStatusBarStyleLightContent to dark (white to black). Now, I figured out if I set,
self.definesPresentationContext = NO;
to the following:
self.definesPresentationContext = YES;
the issue is solved and the UIStatusBar color is preserved. However, another issue arises. When self.definesPresentationContext is set to YES
, upon invocation the search bar shifts down for some reason, coincidently (or rightfully so) right under where the bottom of the UIRefreshControl displays on the tableView.
Setting View-controller based status bar appearance to No is not a solution if you want the view controllers to define how the status bar looks.
My solution consisted of two things:
Make sure the presenting view controller has definesPresentationContext set to YES
Make sure both the view controller that is pushed and the pushing view controller are laid out beneath the navigation bar (set extendedLayoutIncludesOpaqueBars to YES)
As of iOS 10 (maybe earlier?), if you have "View controller-based status bar appearance" set to YES in your Info.plist, simply set the preferredStatusBarStyle in the UIViewController that the UISearchController is included in.
- (UIStatusBarStyle)preferredStatusBarStyle {
return UIStatusBarStyleLightContent;
}
(you don't need to subclass or create a category/extension of UISearchController to override preferredStatusBarStyle... it uses the preferredStatusBarStyle that you set in your UIViewController)
I needed full control over my status bar colour. I use the extensions found here to ensure that the visible view controller is setting the preferred status bar colour.
For me it was therefore necessary to override UISearchController and override preferredStatusBarStyle and return the style I wanted.
If you ViewController is inside a TabBarController then -
Instead of
self.definesPresentationContext = YES;
Use self.tabBarController.definesPresentationContext = YES;
This worked for me in above scenario.
The status bar that is displayed when the search controller is presented (is active) belongs to the search controller. To set the preferred status bar style you must add a category to UISearchController and then override the preferredStatusBarStyle method.
Below is an example of the implementation file of the category:
#implementation UISearchController (Customization)
-(UIStatusBarStyle)preferredStatusBarStyle {
return UIStatusBarStyleLightContent;
}
#end
Or we can write an extension on Swift (version 2, but you can translate it to 3 easily):
extension UISearchController {
override public func preferredStatusBarStyle() -> UIStatusBarStyle{
if Theme.lightTheme() {
return UIStatusBarStyle.Default
}
else {
return UIStatusBarStyle.LightContent
}
}
}
Where Theme is a class that regulate app colour theme.
When performing a search on a dataset via a UISearchBar, the search results successfully display in the UITableViewController's UITableView. However, when scrolling down through the results, the UITableView's rows visibly appear underneath the UINavigationBar and the simulator's status bar.
This obviously is not the look that I'm going for. Ideally, I would like the UISearchBar to act as the UITableView's header with all search results being contained below the UISearchBar's scope buttons, but my attempts have been unsuccessful.
Below is the Storyboard setup of the relevant UITableViewController and its UITableView's properties.
Below is the relevant code that I am using to setup the UISearchController and its UISearchBar.
BallotTunesSearchTableViewController.h
#interface BallotTunesSearchTableViewController : UITableViewController <UISearchControllerDelegate, UISearchResultsUpdating, UISearchBarDelegate>
BallotTunesSearchTableViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
self.appDelegate = [[UIApplication sharedApplication] delegate];
// Initialize the search controller
self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.searchController.searchResultsUpdater = self;
self.searchController.dimsBackgroundDuringPresentation = NO;
// Setup the search bar
self.searchController.searchBar.delegate = self;
self.searchController.searchBar.scopeButtonTitles = [NSMutableArray arrayWithObjects:SongScopeName, ArtistScopeName, AlbumScopeName, nil];
self.tableView.tableHeaderView = self.searchController.searchBar;
}
Update: Note that the UITableViewController is embedded in a UINavigationController, and when setting the translucence of the UINavigationBar to NO, the UISearchBar slides off the view along with the UINavigationBar.
Also note that I am not implementing the UISearchBar in Storyboard (however, I may take that route if I can't get my current setup to work).
After several face palms, it all came down to the lack of this line of code:
self.definesPresentationContext = YES;
Setting the presentation context to YES indicates that the view controller's view should be covered when the view controller presents the UISearchController.
I have a tab bar controller in an iPad app with 6 items. Two of the icons will when you tap at them lead to the same view controller. This view controller has a list of items it will show, it will change slightly depending on which of the tab bar icons you tapped.
How do i set this up with storyboards? Its possible to drag the relationship twice to the same view controller, but then it just shows two of the same icons on the tab bar. I want the two choices to have different icons and name.
Like you've found, you can design the view controller once in the storyboard but won't be able to associate it with the tab bar controller more than once.
What you can do is assign an identifier for it in the identity inspector, and then at runtime you can use the method -[UIStoryboard instantiateViewControllerWithIdentifier:] to instantiate a second copy of the view controller. You can insert that second copy into the tab controller using -[UITabBarController setViewControllers:animated:]
I believe you're better off creating two separate view controllers and placing them in the Tab Bar Controller individually, especially if they're going to load different data. You can place the same view controller into a Tab Bar Controller multiple times, but as far as design goes and how you can manipulate it, it won't make much sense to do it that way.
I got the same question as yours when I am trying to implement a tab bar controller view with 4 tab items, and each tab item reusing the same view controller, and the custom logic for these 4 items are set through the property when the tab bar controller call viewDidLoad. Let me show you what I have done as below:
1. Create a Tab Bar Controller with 4 view controllers
Open the storyboard, and drag a Tab Bar Controller from the object library. And drag another 2 more view controller onto the storyboard as well.
Remember to make a linkage between the tab bar controller and the 2 new view controller.
2. Create a reusing view controller for the 4 tab view
Create a new cocoa touch class, named ViewController, and create you customisation properties in the #interface section. These properties will be set in the tab bar controller viewDidLoad method, so the 4 tab views will use the same view controller, but the properties are not the same.
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
// Define your customisation properties here, so that you can set it in the tab bar controller.
#property (assign, nonatomic) UITableViewCellStyle style;
#end
4. Create a view controller subclass of UITabBarController
Create a new Cocoa Touch class, named UITabViewController, and make it subclass of UITabBarController, and conform UITabBarControllerDelegate.
For my case, I need to show a table view with different 4 cell style in 4 different tabs, so I will set the viewController's style property in the tab bar controller to achieve my target.
UITabViewController.h
#import <UIKit/UIKit.h>
#interface UITabViewController : UITabBarController <UITabBarControllerDelegate>
#end
UITabViewController.m
#import "UITabViewController.h"
#interface UITabViewController ()
#end
#implementation UITabViewController
- (void)viewDidLoad {
// Make UITabViewController as the delegate of UITabBarController
self.delegate = self;
[super viewDidLoad];
// Set-Up the UITableCell style for each tab item
[self.viewControllers enumerateObjectsUsingBlock:^(id viewController, NSUInteger idx, BOOL *stop){
UITableViewCellStyle style;
switch (idx) {
case 0:
style = UITableViewCellStyleDefault;
break;
case 1:
style = UITableViewCellStyleSubtitle;
break;
case 2:
style = UITableViewCellStyleValue1;
break;
case 3:
style = UITableViewCellStyleValue2;
break;
default:
style = UITableViewCellStyleDefault;
break;
}
SEL selector = #selector(setStyle:);
if([viewController respondsToSelector:selector]){
NSInvocation *invk = [NSInvocation invocationWithMethodSignature:[viewController methodSignatureForSelector:selector]];
[invk setSelector:selector];
[invk setTarget:viewController];
[invk setArgument:&style atIndex:2];
[invk invoke];
}
}];
}
Or if you need to set the customisation properties when the user selected different tab items, then you can add a new delegate method in the UITabViewController #implementation section:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
// Check whether the view controller responds to the property setter method
SEL selector = #selector(setMyProperty:);
if([viewController respondsToSelector:selector]){
// Call the setter method with NSInvocation
NSInvocation *invk = [NSInvocation invocationWithMethodSignature:[viewController methodSignatureForSelector:selector]];
[invk setSelector:selector];
[invk setTarget:viewController];
[invk setArgument:&argument atIndex:2];
[invk invoke];
}
}
I had a similar problem and solved it quite easily.
Create a TabBarController in the Storyboard.
In each tab assign a Navigation controller.
Make all Navigation controllers set as Root View Controller the one view controller you want to share between them.
In your View Controller, in ViewDidLoad, create a condition based on the tabBarController.selectedIndex in order to customize the view controller depending on the selected tab. Something like this:
override func viewDidLoad() {
super.viewDidLoad()
if let selectedTabIndex = tabBarController?.selectedIndex {
switch selectedTabIndex:
case 0: // Customize ViewController for tab 1
case 1: // Customize ViewController for tab 2
case 2: // Customize ViewController for tab 3
default: break
}
I don't think you can do what you're trying to do with a UITabBarController. You can add two different instance of the same view controller class if you want. Otherwise, you would have to add a tab bar to a regular UIViewController, and write your own logic to switch between controllers.
I was able to accomplish this by setting the tab titles in viewDidLoad. I created 2 relationships to the same View Controller. I then set the Bar Item Title to "Not Set". Finally, I set the viewDidLoad method as follows:
UITabBarController *tc = (UITabBarController *)self.parentViewController;
NSArray *vcs = tc.viewControllers;
BOOL tabsInitialized=YES;
for (UIViewController *vc in vcs)
{
if ([vc.tabBarItem.title isEqualToString:#"Not Set"])
{
tabsInitialized = NO;
break;
}
}
if (!tabsInitialized)
{
int I=1;
for (UIViewController *vc in vcs)
{
vc.tabBarItem.title = [NSString stringWithFormat:#"Tab %i", i++];
}
}
}
I realize this question was answered a while ago, but none of the solutions mentioned using a UITabBar directly and overriding its UITabBarDelegate tabBar(:,didSelect item:) method, rather than let a UITabBarController handle the selection indirectly.
extension MyListViewController: UITabBarDelegate {
func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
// Set some filter based on the selected item or its tag (tag values can be assigned in IB)
switch item.tag {
// Apply filter to your datasource based on the item.tag
}
// Or if you are using a CoreData NSFetchedResultsController, set its predicate:
// resultsController.predicate = makePredicate(item.tag)
// resultsController.performFetch()
tableView.reloadData()
}
}
By overriding UITabBarDelegate methods directly, you are in direct control of the selection behavior of the tab. So you could re-use the same instance of your UIViewController instead of the UITabBarController insistently creating a new instance of the UIViewController for each tab. For example, in the didSelect method, you could apply a filter to an existing list of items in a UITableView instead of creating a new instance of the list in a new UITableView as the other solutions do.
Note: If you use a UITabBar in your view controller in code or in IB, UIKit does not seem to recognize its presence and "underlapping" scroll views (e.g. UITableView, UICollectionView) will not automatically adjust their contentInset. Nor will anchoring the bottom of the UITabBar lay itself out properly on a device with non-zero safe area margins if you anchor it to the bottom of of the safe area (it will appear to "float" with a gap between itself and the screen-edge).
Solution (part 1): Set the top constraint specially on the UITabBar instance: First anchor the bottom edge of the tab bar to the Superview and anchor the top edge to the bottom edge of the Safe Area and set the constant to 49 its (the standard height of a UITabBar as of this writing). Then it will look correct on devices with and without a safe area margin.
Solution (part 2): You will need to and manually adjust the tableView.contentInset / collectionView.contentInset to ensure content can scroll under the tab bar. You need to ensure the bottom-most item can still be scrolled up above the bottom tab bar:
Disable automatic content inset adjustment in your viewDidLoad():
tableView.contentInsetAdjustmentBehavior = .never
Adjust the UIScrollView.contentInset in an appropriate place, add the following method and call it either in viewDidLoad() or if necessary each time the view lays out in viewDidLayoutSubviews(). (If viewDidLoad() is too early for you, viewWillAppear() is probably too early, too.)
private func adjustScrollViewInsets() {
// This snippet only insets the bottom of the table view, but you may need to adjust both top and bottom edges if you also need to accommodate a top navigation bar.
var contentInset = tableView.contentInset
if let windowInsets = view.window ?? UIApplication.shared.keyWindow?.safeAreaInsets {
contentInset.bottom = windowInsets.bottom
} else {
contentInset.bottom = 0
}
tableView.contentInset = contentInset
}
Tested on SWIFT 5.x
After FAILING multiple times post :-
Implementing tabBar delegates
Setting tabBarController viewControllers array
Implementing tabBar selectedIndex switch case
Finally came some clean hack/solution to mind..
Make new UIViewController() class
Assign it to relative tabBar item
init() existing View Controller from storyboard/xib
Push without animation on viewDidLoad()
class FavouritesViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
guard let homeViewController = storyboard?.instantiateViewController(withIdentifier: "HomeViewController") as? HomeViewController else { return }
homeViewController.filterFavourites = true
navigationController?.pushViewController(homeViewController, animated: false)
}
}
To prevent back gesture navigation so that it won't pop to empty View Controller on left edge swipe
(OPTIONAL: Also hide navigationBar/Back button if applicable in HomeViewController)
override func viewWillAppear(_ animated: Bool) {
navigationController?.interactivePopGestureRecognizer?.isEnabled = false
}
override func viewWillDisappear(_ animated: Bool) {
navigationController?.interactivePopGestureRecognizer?.isEnabled = true
}