I am running into a small problem, I implemented the new iOS 11's style search bar in my app, and I noticed that it disappeared with a slightly different animation from the one in Messages for example. It's faster and less smooth.
Anyone has ever stumble upon this "problem" ?
Here is the code I use :
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.delegate = self
if #available(iOS 11.0, *) {
navigationItem.searchController = searchController
} else {
tableView.tableHeaderView = searchController.searchBar
searchController.searchBar.barTintColor = .white
searchController.searchBar.layer.borderColor = UIColor.white.cgColor
searchController.searchBar.layer.borderWidth = 1
}
definesPresentationContext = true
searchController.searchBar.placeholder = "all_search".localized
EDIT:
I don't know if it will help you, but I am scrolling at a normal pace .
Thanks
Adding
self.extendedLayoutIncludesOpaqueBars = true
to my viewDidLoad solved the issue, your navigation bar must not be translucent and note that extendedLayoutIncludesOpaqueBars = true is being attributed to my main view which holds the tableview.
This happens when your table view doesn't go all the way to the top of the view. Make sure your table view is "behind" the navigation bar and uses extended edges and extend under opaque edges if your navigation bar is opaque.
Try this, it fixes it for me. I used a different UIViewController as the searchResultsUpdater and just set extendedLayoutIncludesOpaqueBars as true.
searchResultsUpdater.extendedLayoutIncludesOpaqueBars = true
searchController.searchResultsUpdater = searchResultsUpdater
UIView.animate(withDuration: 1, animations: {
//your codes to implement
}, completion: nil)
change withDuration: in seconds
Related
Upgrading our application to support iPhone X. How can I add a search bar to the header of a table view and have it within the safe zone? Here is how we currently build the search bar.
let searchController = UISearchController(searchResultsController: nil)
func buildSearchBar() {
self.searchController.searchResultsUpdater = self
self.searchController.hidesNavigationBarDuringPresentation = false
self.searchController.dimsBackgroundDuringPresentation = false
self.searchController.searchBar.sizeToFit()
self.tableView.tableHeaderView = searchController.searchBar
self.definesPresentationContext = true
}
This topic is discussed explicitly in Building Apps for iPhone X video. (Designing for iPhone X also a good video.)
Bottom line, Apple suggests using navigation controller and showing it there:
let searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
if #available(iOS 11, *) {
navigationItem.searchController = searchController
searchController.isActive = true
} else {
present(searchController, animated: true)
}
(By the way, even in the absence of a navigation controller, present-ing the search controller, rather than setting it to be the table header, can prevent it from scrolling out of the safe area.)
Unclear what you mean by "within the safe zone". The table view can scroll, so the search bar is not necessarily "within" any part of the screen; it can be scrolled up behind the sensor area and on beyond.
You'll notice, however, that the native apps do not put the search bar as the header of the table. They put it in the navigation bar. You should do the same. Put the search bar into the navigation bar by setting the searchController of the navigationItem.
I'm having an issue with UISearchController. There have been some reports of erratic behavior in iOS 11, but none of the suggestions have fixed my problem.
The navigation bar is hidden in my app so I just want to place the search bar between two buttons on the main screen. I put UIView in the storyboard to serve as the superview for the search bar. When activated the results controller is a straight UITableViewController.
Everything is in-place when the app launches. When I access the search bar it just to the top of the screen, leaving it's parent view behind. Everything functions ok, but when I hide the table view, the search bar actual goes a bit lower than it was when it started. Here's the setup code:
let locationSearchTable = storyboard!.instantiateViewController(withIdentifier: "LocationSearchTable") as! LocationSearchTable
searchController = UISearchController(searchResultsController: locationSearchTable)
searchController.searchResultsUpdater = locationSearchTable
searchController.delegate = self
locationSearchTable.mapView = mapView
locationSearchTable.handleMapSearchDelegate = self
locationTableController = locationSearchTable
let searchBar = searchController!.searchBar
//searchBar.searchBarStyle = UISearchBarStyle.prominent
searchBar.sizeToFit()
searchBar.placeholder = "Search..."
searchViewHolder.addSubview(searchBar)
searchBar.frame = searchViewHolder.bounds
searchBar.autoresizingMask = [.flexibleWidth, .flexibleHeight]
searchController.dimsBackgroundDuringPresentation = true
definesPresentationContext = false
I have tried many, many approaches to fixing this. I'm wondering if I misunderstood an earlier suggestion. Any advice is welcome.
I'd the same issue. If your navbar is not translucent try to put this in viewDidLoad:
extendedLayoutIncludesOpaqueBars = true
This one has kept be up a few days. I think the easiest way to illustrate my issue is with this 10 second gif.
Description
As you can see, when you go back after pushing to a search result, the segmented top bar disappears when you go back, but when I switch to the tab with "Tise" in the header and back, it resets and works properly.
As seen in the below screenshot, my issue is that the top layout guide gets offset underneath the navigation bar, which makes the segmented bar hide underneath it.
Code
My search controller is an extremely normal implementation.
/* Search controller */
let exploreSearchController = StandaloneExploreSearchResultController.initFromStoryboard(type: .top)
searchController = UISearchController(searchResultsController: exploreSearchController)
searchController?.searchResultsUpdater = exploreSearchController
searchController?.delegate = self
searchController?.searchBar.searchBarStyle = .minimal
searchController?.searchBar.isTranslucent = false
searchController?.searchBar.backgroundColor = .clear
searchController?.hidesNavigationBarDuringPresentation = false
searchController?.dimsBackgroundDuringPresentation = false
searchController?.searchBar.tintColor = #colorLiteral()
navigationItem.titleView = searchController?.searchBar
definesPresentationContext = true
and I push the result controllers in StandaloneExploreSearchResults with
presentingViewController?.navigationController?.pushViewController(viewController, animated: true)
For every new view controller, I update the navigation bar style, which I suspect might be triggering it. If I disable this function, I get different offset bugs, as seen in the following gif.
func updateNavigationBarStyle(viewController: UIViewController) {
let style = (viewController as? NavigationControllerStyling)?.preferredStyle() ?? .default
print(#file.components(separatedBy: "/").last!,":",#line,"-",#function, viewController.classForCoder)
//Showhide
UIApplication.shared.setStatusBar(hidden: style.statusBar.hidden, style: style.statusBar.style)
setNavigationBarHidden(style.hidden.hidden, animated: style.hidden.animated)
navigationBar.setCustomShadow(hidden: style.shadowHidden)
//Colors
navigationBar.tintColor = style.tintColor
navigationBar.barTintColor = style.barTintColor
navigationBar.backgroundColor = style.backgroundColor
navigationBar.setBackgroundImage(style.backgroundImage, for: .default)
navigationBar.titleTextAttributes = style.titleTextAttributes
navigationBar.isTranslucent = style.translucent
navigationBar.hairlineImageView?.isHidden = true //Always hide the native shadow
}
Question
Is there a way to either force the auto layout reload that switching tabs triggers (I've tried all the methods I could find with no success). or fix the bug somehow?
Well, that solved it. I guess setting the colors and/or images somehow fiddled with the opaque property.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
extendedLayoutIncludesOpaqueBars = true
}
Try this code in viewDidLoad -
self.edgesForExtendedLayout = []
I have a UITableViewController where I have placed a search bar in the tableHeaderView. It all looks fine like the picture below.
But, the problem is when it is presented:
As you can see, it is mostly hidden above the top of the screen.
Here is the code I used to set it up in the tableview controller's viewDidLoad:
searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.delegate = self
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search Presets..."
searchController.searchBar.delegate = self
searchController.searchBar.barStyle = .blackTranslucent
searchController.hidesNavigationBarDuringPresentation = true;
self.tableView.tableHeaderView = searchController.searchBar
self.tableView.contentOffset = CGPoint(x:0, y:searchController.searchBar.frame.size.height);
If I print the frame of the searchbar, it's origin is (0,0).
I have tried everything I can think of, but nothing works
I figured out that if I check Translucent in the Navigation Bar's Attributes Inspector in IB the issue is resolved.
This leads me to believe that leaving that unchecked and setting extendedLayoutIncludesOpaqueBars to true would also work, but I found this not to be the case.
The structure:
View1 (click a button) -> present modally (MyModalView: UITableViewController)
MyModalView has UISearchController embedded. The searchBar of UISearchController is placed in MyModalView.tableView.tableHeaderView.
It's been working fine since iOS 8.0. However on iOS 9, the searchBar disappear when the UISearchController is active. Please take a look at theses pictures below
The modal view:
UISearchController active on iOS 8:
UISearchController active on iOS 9:
The very standard code:
override func viewDidLoad() {
super.viewDidLoad()
// Dynamically create a search controller using anonymous function
self.resultSearchController = ({
let controller = UISearchController(searchResultsController: nil)
controller.searchResultsUpdater = self
controller.dimsBackgroundDuringPresentation = false
controller.searchBar.sizeToFit()
controller.searchBar.delegate = self
self.tableView.tableHeaderView = controller.searchBar
return controller
})()
// Auto sizing row & cell height
self.tableView.estimatedRowHeight = 130
self.tableView.rowHeight = UITableViewAutomaticDimension
self.definesPresentationContext = true
// No footer for better presentation
self.tableView.tableFooterView = UIView.init(frame: CGRectZero)
}
This issue also happens in iOS 9.1 beta...
Any idea / pointer would be deeply appreciated
Cheers.
I'm not sure what exactly is the problem but I 'fixed' it by:
self.searchController.hidesNavigationBarDuringPresentation = NO;
self.definesPresentationContext = NO;
My guess is that UISearchController is doing something funky when it is trying to present as a navigation bar. So, this is a hack but it at least doesn't block the user. The search bar doesn't do the cool animation and cover up the navigation bar.
It seems all of us got the same problem but they were solved in different ways. However none of the suggested answers worked for me :(. Nevertheless thank you all for your time.
I got a solution that solved my problem. It is setting Extend Edges - Under Opaque Bars of my (MyModalView: UITableViewController) to true in the Storyboard using Interface Builder.
In summary:
MyModalView: UITableViewController, in Storyboard using Interface Builder has
Extend Edges:
- Under Top Bars ticked
- Under Bottom Bars ticked
- Under Opaque Bars ticked
I found it's the simulated metrics (top bar) in storyboard that's cause this problem.
In my case, the following lines work, but I still don't know why.
- (void)willPresentSearchController:(UISearchController *)searchController {
// do something before the search controller is presented
self.navigationController.navigationBar.translucent = YES;
}
-(void)willDismissSearchController:(UISearchController *)searchController
{
self.navigationController.navigationBar.translucent = NO;
}
I had to
self.aNavigationController?.extendedLayoutIncludesOpaqueBars = true
I found a similar question here but in my case it was not on the viewDidLoad method. I had to try different views until it worked. Now I can have both a custom navigation bar color and the search bar,
Thanks #wiles duan and #Techprimate
In my case, I fixed this issue by setting:
self.definesPresentationContext = NO;
And implement the following 2 methods in UISearchControllerDelegate
- (void)willPresentSearchController:(UISearchController *)searchController {
// do something before the search controller is presented
self.navigationController.navigationBar.translucent = YES;
}
-(void)willDismissSearchController:(UISearchController *)searchController
{
self.navigationController.navigationBar.translucent = NO;
}
I fixed it in my case by removing
definesPresentationContext = true
I didn't test yet if there are any disadvantages of removing this!
I had the same problem, and when I debugged the UI on Xcode I found that the UISearchBar view was moved to another view and the width was zeroed.
I fixed it by setting definesPresentationContext property of the UISearchController to false, and setting it true for the containing UITableViewController.
I added only one line to your viewDidLoad().
override func viewDidLoad() {
super.viewDidLoad()
// Dynamically create a search controller using anonymous function
self.resultSearchController = ({
let controller = UISearchController(searchResultsController: nil)
controller.searchResultsUpdater = self
controller.dimsBackgroundDuringPresentation = false
controller.definesPresentationContext = false // Disable the presentation controller
controller.searchBar.sizeToFit()
controller.searchBar.delegate = self
self.tableView.tableHeaderView = controller.searchBar
return controller
})()
// Auto sizing row & cell height
self.tableView.estimatedRowHeight = 130
self.tableView.rowHeight = UITableViewAutomaticDimension
self.definesPresentationContext = true // This one remains the same
// No footer for better presentation
self.tableView.tableFooterView = UIView.init(frame: CGRectZero)
}
I don't have a navigation bar in this place of an app. None of other SO posts helped me, so I've fixed it this way:
- (void)layoutSubviews
{
[[[self searchController] searchBar] sizeToFit];
}
Setting the navigationBar permanently to translucent in storyboard solved my problem.
It works
override func viewDidLoad() {
super.viewDidLoad()
self.extendedLayoutIncludesOpaqueBars = !self.navigationController!.navigationBar.translucent
}
If you want to hide you navigation bar, and present search controller full screen, set the following on your navigation bar and search bar won't dissapper:
navigationController?.navigationBar.translucent = true
sc.hidesNavigationBarDuringPresentation = false
does the trick for me
lazy var searchController:UISearchController = {
let sc = UISearchController(searchResultsController: nil)
sc.searchResultsUpdater = self
sc.obscuresBackgroundDuringPresentation = false
sc.searchBar.placeholder = "Search"
sc.hidesNavigationBarDuringPresentation = false
return sc
}()
None of them worked for me, I fixed it using this hack
func position(for bar: UIBarPositioning) -> UIBarPosition {
if UIDevice.current.userInterfaceIdiom == .pad {
return .top
} else {
if iOSVersion <= 9 {
return .top
}
return .topAttached
}
}