after the new update, I've noticed that my UISearchController isn't acting like it did before.
First, the UITextField no longer has a white background. I was trying to figure out why this is happening, but have had no luck. This is how I'm creating it.
var resultsSearchController = UISearchController(searchResultsController: nil)
self.resultsSearchController.delegate = self
let searchBar = self.resultsSearchController.searchBar
self.resultsSearchController.searchResultsUpdater = self
self.resultsSearchController.obscuresBackgroundDuringPresentation = false
self.resultsSearchController.extendedLayoutIncludesOpaqueBars = true
searchBar.sizeToFit()
self.tableView.tableHeaderView = searchBar
searchBar.placeholder = "Catalog Search"
searchBar.barTintColor = UIColor.darkAqua
As best I can tell, the default UITextField default appearance seems to have changed is my guess.
Just wondering how to change it back, if possible.
---EDIT---
I attempted to do as suggested and added this code to viewDidLoad()
if #available(iOS 13.0, *) {
overrideUserInterfaceStyle = UIUserInterfaceStyle.light
} else {
// Fallback on earlier versions
}
as well as adding this to the UISearchController code
if #available(iOS 13.0, *) {
self.resultsSearchController.overrideUserInterfaceStyle = UIUserInterfaceStyle.light
} else {
// Fallback on earlier versions
}
No combination of both of those codes was able to change it so that that UITextField presented as expected.
Well, turns out I'm dumb. Its much easier that I was trying to make it for myself.
All I ended up doing was accessing the UITextField in the searchBar for the UISearchController
Adding this:
searchBar.searchTextField.backgroundColor = UIColor.white
With the code I already had seems to make it look normal again.
Related
I faced a weird problem. I wanted to change the colors of my tabBar in just one of my view controllers of my tabBar. How do I achieve this in iOS > 13?
After searching a lot and finding no working solutions, I succeeded by luck.
I found out that you must set an appearance object before I can change them!!
But if you set appearance before the override function endAppearanceTransition() of UITabbar it is working, but not anymore. finally, this way worked:
Set an empty appearance object at viewDidLoad of one of the view Controllers or UITabbarViewcontroller to be executed one time:
override func viewDidLoad() {
super.viewDidLoad()
tabBarController?.tabBar.standardAppearance = UITabBarAppearance()
}
Then you can use updating like this at anytime:
let attrs = [NSAttributedString.Key.foregroundColor: UIColor.green]
tabBarController?.tabBar.backgroundColor = barColor
tabBarController?.tabBar.standardAppearance.stackedLayoutAppearance.selected.iconColor = .green
tabBarController?.tabBar.standardAppearance.stackedLayoutAppearance.normal.iconColor = .green
tabBarController?.tabBar.standardAppearance.stackedLayoutAppearance.normal.titleTextAttributes = attrs
tabBarController?.tabBar.standardAppearance.stackedLayoutAppearance.selected.titleTextAttributes = attrs
After looking for updated (iOS 13) answers, I didn't find any solutions to this simple problem : How to change the textColor of the placeholder in an UISearchBar ?
My app doesn't handle Light/Dark mode. I don't want the system to change my UIPlaceHolder text color. I want it to be always white.
if #available(iOS 13.0, *) {
let attrString = NSMutableAttributedString(string: "My PlaceHolder")
attrString.addAttributes([NSAttributedString.Key.foregroundColor: UIColor.white], range: NSRange(location: 0, length: attrString.length))
searchController.searchBar.searchTextField.attributedPlaceholder = attrString
}
I expected this code to work. I thought the new property searchTextField would have made it easier to customize my UISearchBar.
EDIT:
This code kind of works in the viewDidAppear method :
if #available(iOS 13.0, *) {
searchController.searchBar.searchTextField.attributedPlaceholder = NSAttributedString(string: "My PlaceHolder", attributes: [NSAttributedString.Key.foregroundColor: UIColor.white.withAlphaComponent(0.80)])
}
The issue is that the color is changing when you scroll up and down.
As you already mentioned, your code works only in viewDidAppear, which makes the placeholder to flicker from the default gray color to the preferred color.
However, there seem to be a time before viewDidAppear (I couldn't figure it out when exactly), to change the placeholder before the view actually appears.
I suppose, this may be connected to how iOS handles light/dark mode and/or an iOS bug.
The solution I came out with that works around the issue:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if #available(iOS 13.0, *) {
let placeholder = NSAttributedString(string: "Search",
attributes: [
.foregroundColor: UIColor.white
])
let searchTextField = searchBar.searchTextField
// Key workaround to be able to set attributedPlaceholder
DispatchQueue.global().async {
DispatchQueue.main.async {
searchTextField.attributedPlaceholder = placeholder
}
}
}
}
There seem to be no performance and/or other downside to this method.
If anybody else comes with a better approach, feel free to collaborate.
you can set this with UITextField appearance property. check this line of code
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).defaultTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
I guess the reason why it doesn't work is probably the searchController.searchBar.searchTextField = nil you got.
searchTextField is a new property for iOS 13, which can be done if you only support >= iOS 13. If you want to adapt to the previous version of iOS 13, you can traverse UISearchBar to find UISearchBarTextField and directly set the found UISearchBarTextField.
The code I looked up is probably like this, I put it in the Category of UIView.
- (UIView *)findChildViewClass:(Class)childViewClass fromView:(UIView *)fromView{
for (UIView *subView in fromView.subviews) {
if ([subView isMemberOfClass:childViewClass]) {
return subView;
}
UIView *finalView = [self findChildViewClass:childViewClass fromView:subView];
if (finalView) {
return finalView;
}else{
continue;
}
}
return nil;
}
When used, you can customize a searchTextField property to inherit from UITextField to save the found value.
_searchTextField = (UITextField *)[searchBar findChildViewClass:NSClassFromString(#"UISearchBarTextField") fromView: searchBar];
This is what I use now, it is working, I hope to be useful to you.
I have my UISearchBar set up as follows:
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false // Allow user to tap on results
searchController.searchBar.placeholder = "Search patients" // Placeholder
searchController.searchBar.barStyle = .blackOpaque
searchController.searchBar.tintColor = colors.text // Cancel button tint
navigationItem.searchController = searchController // Set the searchController
navigationItem.hidesSearchBarWhenScrolling = true // Auto-hide search when user scrolls
This is how it looks on iOS 12:
vs iOS 13:
What's changed in iOS 13? I've tried going through the different barStyles, and also setting .isTranslucent to false - no effect for either. Light/dark mode also don't change anything.
The other change is hiding the search bar - on iOS 12 if I scrolled upwards a little the search bar would hide (didn't matter if the table was populated or not). With iOS 13, once the search bar has appeared (ie the user has swiped down), it cannot be hidden again. Anyone know of a fix for this too?
I get something similar problem with you. I don't know why this happen in currently iOS 13 and work properly in older version. But i have found the solution by adding this function to your searchBar.
if #available(iOS 13.0, *) {
searchBar.searchTextField.backgroundColor = UIColor.white
}
Preview after fixing:
How about to use searchBarStyle as default and change the searchTextField background color?
if #available(iOS 13.0, *) {
searchBar.searchBarStyle = .default
searchBar.searchTextField.backgroundColor = UIColor.black.withAlphaComponent(0.1)
}
For setting in globally like in AppDelegate:
if #available(iOS 13, *) {
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).backgroundColor = .anyColor
}
searchController.searchBar.searchTextField.backgroundColor = UIColor.black does the job as a workaround. The selector is new in iOS 13.
I've filed a report on feedback assistant anyway as I do believe this to be unexpected behaviour.
iOS 13+.
searchController.searchBar.searchTextField.backgroundColor = UIColor.white
I'm using a UISearchController for search in a UITableViewController that also supports pull-to-refresh via UIRefreshControl.
The setup is very simple in a reduced Demo project
override func viewDidLoad() {
extendedLayoutIncludesOpaqueBars = true
title = searchTerm ?? "Search"
super.viewDidLoad()
setupSearch()
setupRefresh()
}
private func setupSearch() {
searchController.searchResultsUpdater = self
navigationItem.searchController = searchController
definesPresentationContext = true
//
// If this is set to `true` (which is also the default),
// UISearchBar and UIRefreshcontroll are buggy
//
navigationItem.hidesSearchBarWhenScrolling = true
}
private func setupRefresh() {
refreshControl = UIRefreshControl()
refreshControl?.addTarget(self, action: #selector(refresh), for: .valueChanged)
}
This worked in iOS 12, but now in iOS 13 (compiled for iOS 13 with Xcode 11 GM), the Refresh Animation is broken
The only "fix" I have found so far is to set navigationItem.hidesSearchBarWhenScrolling to false, but this obviously causes the Searchbar to always stay on screen, even when scrolling.
Here is a sample project demonstrating the issue: https://github.com/iv-mexx/UISearchControl-UIRefreshControl-iOS13-Bug/tree/feature/ios13
Update: This still remains broken in Xcode 11 GM Seed 2
If turning on large titles is an option for your app, this seems to workaround the issue as well.
This might be why Apple isn't running into the issue in their own apps.
I'm trying to add a UISearchController to a UIViewController that contains a UITableView (and an MKMapView too, but hopefully that's not the problem). I followed Ray Wenderlich's tutorial but I can't get the same result in terms of behaviour.
Here is my viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
// Setup the Search Controller
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = NSLocalizedString("Search references by project, customer or city", comment: "")
if #available(iOS 11.0, *) {
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = true
} else {
tableView.tableHeaderView = searchController.searchBar
}
definesPresentationContext = true
self.modeSelector.layer.cornerRadius = 5.0
if let split = splitViewController {
let controllers = split.viewControllers
detailViewController = (controllers[controllers.count - 1] as! UINavigationController).topViewController as? ReferenceViewController
}
self.navigationItem.rightBarButtonItem?.isEnabled = false
}
Note that the #available test in the middle is because I need to support iOS up to 9.1.
Now I see several problems:
The search bar appears right away and I can't hide it by scrolling
When I focus the search bar, the top of the tableview doesn't stick to the bottom of the navigation item:
The only major difference I see with Ray Wenderlich's sample project is that since I created my project with Xcode 9, my storyboard doesn't use top and bottom layout guides, but safe areas. Don't know if it's relevant, but that's the only thing I see.
Any idea what's going on and how I could fix this?
If you need to support iOS up to 9.1, you probably use emulator with version older than 9.1. Therefore, "maybe" obscuresBackgroundDuringPresentation doesn't affect the searchController properly, since it's only available on iOS 9.1 or newer. Add dimsBackgroundDuringPresentation to support up to 9.1:
if #available(iOS 9.1, *) {
searchController?.obscuresBackgroundDuringPresentation = false
} else {
searchController?.dimsBackgroundDuringPresentation = false
}
If this doesn't help to display as expected, I'm almost sure that the problem is about your layout constraints. Please add your current constraints if you couldn't bring your layout in compliance with safe area.
use this below line of code into your viewDidload
self.navigationController?.navigationBar.isTranslucent = false
Hope this will help you
If you are using xcode 9 (ios 11). Then the thing you really want to do is -
Use the new Broader navigation bars which are the new highlights in the ios 11 devices. But as there are many who have not shifted to ios-11, previous version devices are also taken into consideration.
For adding the search bar to the newer navigation bars I have used the following function which gives a search bar on scrolling and hides it when user scrolls the page.
func addSearchBar() {
if #available(iOS 11.0, *) {
let sc = UISearchController(searchResultsController: nil)
sc.delegate = self
let scb = sc.searchBar
scb.tintColor = UIColor.white
scb.barTintColor = UIColor.white
//Change the colors as you like them
if let textfield = scb.value(forKey: "searchField") as? UITextField {
textfield.textColor = UIColor.blue
if let backgroundview = textfield.subviews.first {
// Background color
backgroundview.backgroundColor = UIColor.white
// Rounded corner
backgroundview.layer.cornerRadius = 10;
backgroundview.clipsToBounds = true;
}
}
if let navigationbar = self.navigationController?.navigationBar {
navigationbar.barTintColor = UIColor.white
}
navigationItem.searchController = sc
navigationItem.hidesSearchBarWhenScrolling = true
}else{
//add the logic for previous version devices here.
}
I have also set the
self.navigationController?.navigationBar.prefersLargeTitles = true; in viewDidLoad as there is a bug in xcode9 and setting it from the interface builder does not work(yet).
The following method has been taken from here