I would like to know how to hide or not display the UISearchBar cross that appears in the textField fo the UISearchBar
I have tried using this
filterSearchBar.showsCancelButton = NO;
However this is an actual cancel button not the small grey cross, so I would like to know if there is an equivalent for the small grey button that shows in the UISearchBar.
You need to get the textField of the Search Bar:
UITextField *textField = [searchBar valueForKey:#"_searchField"];
textField.clearButtonMode = UITextFieldViewModeNever;
hope this help! =)
There's a better way to do this, and you don't have to use private APIs or traverse subviews to do it, so this solution is App Store safe.
UISearchBar has a built-in API for doing this:
[UISearchBar setImage:forSearchBarIcon:state]
The SearchBar icon key you want is UISearchBarIconClear, and you want the UIControlStateNormal state. Then give it a clear image for the image, and you're done.
So, it should look like this:
[searchBar setImage:clearImage forSearchBarIcon:UISearchBarIconClear state:UIControlStateNormal];
Swift 4
Adding to Alexander's answer and block user interaction on clear button:
To hide button:
searchBar.setImage(UIImage(), for: .clear, state: .normal)
To disable user interaction on the clear button, simply subclass UISearchBar
class CustomSearchBar: UISearchBar {
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let view = super.hitTest(point, with: event)
if view is UIButton {
return view?.superview // this will pass-through all touches that would've been sent to the button
}
return view
}
}
Based on #Gines answer, here is the Swift version:
func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
guard let firstSubview = searchBar.subviews.first else { return }
firstSubview.subviews.forEach {
($0 as? UITextField)?.clearButtonMode = .never
}
}
Swift 5
Tested on iOS 13
One liner working for me:
searchBar.searchTextField.clearButtonMode = .never
You can also set it to .whileEditing to have it displayed when the user is typing and then removed when the search bar loses focus.
Swift 3, based on #Alexsander answer:
searchBar.setImage(UIImage(), for: .clear, state: .normal)
You can remove the clear text button for all UISearchBar instances:
[UITextField appearanceWhenContainedInInstancesOfClasses:#[[UISearchBar class]]].clearButtonMode = UITextFieldViewModeNever;
Swift 5
Just add a single line below
searchBar.searchTextField.clearButtonMode = .never
Swift 3 solution :
extension UISearchBar{
var textField : UITextField{
return self.value(forKey: "_searchField") as! UITextField
}
}
Usage :
searchBar.textField.clearButtonMode = .never
I tried different solutions about this issue, even the one selected in this post, but they didn't work.
This is the way I found to solve this issue:
UIView *subview = [[searchBar subviews] firstObject]; //SearchBar only have one subview (UIView)
//There are three sub subviews (UISearchBarBackground, UINavigationButton, UISearchBarTextField)
for (UIView *subsubview in subview.subviews)
{
//The UISearchBarTextField class is a UITextField. We can't use UISearchBarTextField directly here.
if ([subsubview isKindOfClass: [UITextField class]])
{
[(UITextField *)subsubview setClearButtonMode:UITextFieldViewModeNever];
}
}
Try this:
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
UITextField *textField = [searchBar valueForKey:#"_searchField"];
textField.clearButtonMode = UITextFieldViewModeNever;
}
In Case of Swift 2.3 just use :
var searchBar = UISearchBar();
searchBar.frame = CGRectMake(0, 0, 00, 20))
for subview: UIView in (searchBar.subviews.first?.subviews)!
{
if (subview.isKindOfClass(UITextField) )
{
let textFieldObject = (subview as! UITextField)
textFieldObject.clearButtonMode = .Never;
}
}
Swift 2.3, based on #Alexsander answer:
searchBar.setImage(UIImage(named: "SearchClearIcon"), forSearchBarIcon: UISearchBarIcon.Clear, state: UIControlState.Highlighted)
searchBar.setImage(UIImage(named: "SearchClearIcon"), forSearchBarIcon: UISearchBarIcon.Clear, state: UIControlState.Normal)
Converting Soto_iGhost's answer to Swift 4:
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
let textField: UITextField = searchBar.value(forKey: "_searchField") as! UITextField
textField.clearButtonMode = .never
}
If you have an outlet of UISearchBar the you can write above code anywhere in your class.
thijsonline's answer in swift:
(UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self])).clearButtonMode = .never
Related
I can display and hide keyboard. There is a problem: when I tap something in the searchBar, there is a X symbol in the left of the searchBar and a cancel button. If I click cancel button first and then click the X symbol, I will got an fatal error: Index out of range.
So I want to hide the “x” symbol rather than “cancel” button. Is this possible?
Get the textfield and hide it.
UITextField *textField = [searchBar valueForKey:#"_searchField"];
textField.clearButtonMode = UITextFieldViewModeNever;
or Swift you can alwasy extend the search bar and override it.
class NoCancelButtonSearchController: UISearchController {
let noCancelButtonSearchBar = NoCancelButtonSearchBar()
override var searchBar: UISearchBar { return noCancelButtonSearchBar }
}
class NoCancelButtonSearchBar: UISearchBar {
override func setShowsCancelButton(_ showsCancelButton: Bool, animated: Bool) { /* void */ }
}
Swift 5
hide the x icon within the UISearchBar:
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).clearButtonMode = .never
There are older version of this question for older versions of iOS no longer works due to the layout changes in UISearchBar.
I've tried the following to completely remove the background color of UISearchBar but it doesn't work. (I tried to look up the hierarchy views of it but xCode kept crashing for this option.)
private func clearBackgroundColor() {
for view in self.subviews {
view.backgroundColor = UIColor.clear
for subview in view.subviews {
subview.backgroundColor = UIColor.clear
}
}
}
Any ideas or suggestions?
Thanks!!
private func clearBackgroundColor() {
guard let UISearchBarBackground: AnyClass = NSClassFromString("UISearchBarBackground") else { return }
for view in self.subviews {
for subview in view.subviews where subview.isKind(of: UISearchBarBackground) {
subview.alpha = 0
}
}
}
This is what I did in the end that worked. Thanks all for your answers.
I think you are mention about BarTintColor of search bar
try this:
searchBar.barTintColor = .white
Just set the Search Bar style to .Minimal in Interface Builder or code and the background will go transparent.
Try this.
class CustomSearchBar: UISearchBar {
override func layoutSubviews() {
super.layoutSubviews()
clearBackgroundColor() // function in the question
}
}
private func clearBackgroundColor() {
for view in self.subviews {
view.backgroundColor = UIColor.clear
for subview in view.subviews {
subview.backgroundColor = UIColor.clear
}
}
}
try set backgroundimage:
[searchBar setBackgroundImage:[UIImage new]];
let searchBar = UISearchBar()
searchBar.backgroundImage = UIImage()
You can change search style to "Minimal" in Interface Builder
I'm trying to achieve the same effect as Apple's Contacts app (left screenshot). The cancel button in UISearchBar is enabled even when the keyboard is dismissed. My app behaves differently (right screenshot). The cancel button automatically becomes disabled when the keyboard is dismissed. The user is forced to tap the cancel button one time to enable it and then another time to actually trigger the dismissal. This is not good user experience. How would I always keep the cancel button enabled like Apple's Contacts app?
Technical Details:
I'm not using UISearchDisplayController due to some design requirements. This is just a UISearchBar with my own custom search controller. The cancel button is shown using [self.searchBar showsCancelButton:YES animated:YES]. The keyboard is dismissed using [self.searchBar resignFirstResponder].
Call to [self.searchBar resignFirstResponder] will make the cancel button disabled. Hence, you should always update cancel button to enable after calling it.
Objective-C
[searchBar resignFirstResponder];
UIButton *cancelButton = (UIButton *)[searchBar valueForKey:#"cancelButton"];
[cancelButton setEnabled:YES];
Swift
searchBar.resignFirstResponder()
if let cancelButton = searchBar.value(forKey: "cancelButton") as? UIButton {
cancelButton.isEnabled = true
}
In my experience, view.endEditing(true) is the problem. Because it's also called .resignFirstResponder if there's a UITextField inside the view, which is contained in UISearchBar.
https://developer.apple.com/reference/uikit/uiview/1619630-endediting
For Swift 4.0
if let cancelButton : UIButton = searchBar.value(forKey: "cancelButton") as? UIButton{
cancelButton.isEnabled = true
}
This is what worked for me to handle any dismissal such as searchBar.resignFirstResponder(), view.endEditing(false), interactive swipe to dismiss, presenting a view controller, etc.
extension ViewController: UISearchBarDelegate {
func searchBarShouldEndEditing(_ searchBar: UISearchBar) -> Bool {
//cancel button becomes disabled when search bar isn't first responder, force it back enabled
DispatchQueue.main.async {
if let cancelButton = searchBar.value(forKey: "cancelButton") as? UIButton {
cancelButton.isEnabled = true
}
}
return true
}
}
Making sure to set searchBar.delegate = self.
You can use the runtime API to access the cancel button.
UIButton *btnCancel = [self.searchBar valueForKey:#"_cancelButton"];
[btnCancel setEnabled:YES];
As far as your question is concerned, there is no way you can enable the cancel button when the keyboard is dismissed, like there is no callback as such.
Since iOS 7 all the subview of UISearchBar are one level deeper. This should work:
for (UIView *subView in searchBar.subviews) {
for (UIView *secondLevelSubview in subView.subviews) {
if ([view isKindOfClass:[UIButton class]]) {
[(UIButton *)view setEnabled:YES];
}
}
Still hacky and can easily break in the next iOS version.
You could do this:
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
[self enableCancelButton];
}
- (void)enableCancelButton {
for (UIView *view in _seachBar.subviews) {
if ([view isKindOfClass:[UIButton class]]) {
[(UIButton *)view setEnabled:YES];
}
}
}
BUT this is a pretty hackish method and I'm fairly certain it's generally frowned upon by Apple and could potentially lead to the app being rejected. As far as I know, there doesn't seem to be any other way to do what you're trying to do.
Here's a recursive solution that is working for me.
func enableButtons(_ view:UIView) {
for subView in view.subviews {
enableButtons(subView)
}
if let buttonView = view as? UIButton {
buttonView.isEnabled = true
}
}
Try this simple solution, works perfect for me
extension UISearchBar {
func enableCancelButton(in view: UIView) {
view.subviews.forEach {
enableCancelButton(in: $0)
}
if let cancelButton = view as? UIButton {
cancelButton.isEnabled = true
cancelButton.isUserInteractionEnabled = true
}
}
}
extension ViewController: UISearchBarDelegate {
func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
DispatchQueue.main.async {
searchBar.enableCancelButton(in: searchBar)
}
}
}
Implement the below searchBarShouldEndEditing delegate method in your code. Hope it will helpful.
(BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar
{
[[searchBar valueForKey:#"_cancelButton"] setEnabled:YES];
return YES;
}
Here's a simple way:
searchBar.resignFirstResponder()
(searchBar.value(forKey: "_cancelButton") as? UIButton)?.isEnabled = true
I want to add a button (bar) inside a UISearchbar and another one just outside the UISearchbar as shown in the image. Any help on this appreciated.
Thanks in advance
Naveen
Edit :
As stated by #NicolasMiari in the comments :
This no longer works post-iOS 7, since the bookmarks button is rendered inside the bar's input text field.
For the button inside the search bar, you can use the bookmark button and change its image. You simply go to your storyboard (if you use one), select the search bar, and activate the option "Shows Bookmarks Button". Then, in your code, set the image you want :
[_searchBar setImage:[UIImage imageNamed:#"My-Custom-Image"] forSearchBarIcon:UISearchBarIconBookmark state:UIControlStateNormal];
You can detect a click on this button with the following delegate method :
- (void)searchBarBookmarkButtonClicked:(UISearchBar *)searchBar {
NSLog(#"click");
}
Swift 4
class ViewController: UIViewController {
var searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
searchController.delegate = self
searchController.searchBar.delegate = self
searchController.searchBar.showsBookmarkButton = true
searchController.searchBar.setImage(UIImage(named: "myImage"), for: .bookmark, state: .normal)
}
}
extension ViewController: UISearchBarDelegate {
func searchBarBookmarkButtonClicked(_ searchBar: UISearchBar) {
print("click")
}
}
The fastest way to add a button in UISearchBar is to update the bookmark button like this:
[self.searchDisplayController.searchBar setImage:[UIImage imageNamed:#"customImage.png"] forSearchBarIcon:UISearchBarIconBookmark state:UIControlStateNormal];
If you need to adjust the offset,
[self.searchDisplayController.searchBar setPositionAdjustment:UIOffsetMake(-10, 0) forSearchBarIcon:UISearchBarIconBookmark];
Don't forget to activate the option "Shows Bookmarks Button" in story board.
I am not able to clear search bar I have tried to make it clear by setting its background color clear and I have also placed one image under searchbar
I have also made clear background of searchbar
for (UIView *subview in self.searchBarHome.subviews) {
if ([subview isKindOfClass:NSClassFromString(#"UISearchBarBackground")]) {
[subview removeFromSuperview];//please help me to make clear background of uisearchbar
break;
}
}
[self.searchBarHome setBackgroundColor:[UIColor clearColor]];
For iOS7+, all you need to do is:
[self.searchBarHome setBackgroundColor:[UIColor clearColor]];
[self.searchBarHome setBarTintColor:[UIColor clearColor]]; //this is what you want
NOTE: This will not work for iOS6
For iOS6+, the following will take care of it even in iOS7:
[self.searchBarHome setBackgroundColor:[UIColor clearColor]];
[self.searchBarHome setBackgroundImage:[UIImage new]];
[self.searchBarHome setTranslucent:YES];
Here's my solution in Swift 3 (a combo of Scarafone's and Andrew2M's answers):
for view in searchBar.subviews.last!.subviews {
if type(of: view) == NSClassFromString("UISearchBarBackground"){
view.alpha = 0.0
}
}
or alternatively:
searchBar.barTintColor = UIColor.clear
searchBar.backgroundColor = UIColor.clear
searchBar.isTranslucent = true
searchBar.setBackgroundImage(UIImage(), for: .any, barMetrics: .default)
UISearchBar includes two subviews,they are 'UISearchBarBackground' and 'UITextField'. In IOS8, you need to remove 'UISearchBarBackground' to clear it.
for (UIView *subview in [[yourSearchBar.subviews lastObject] subviews]) {
if ([subview isKindOfClass:NSClassFromString(#"UISearchBarBackground")]) {
[subview removeFromSuperview];
break;
}
}
Removing the UISearchBarBackground may result in unknown behavior particularly if as you begin to use the element in more advanced ways.
Ruozi's answer was my preferred solution for grabbing the UISearchBarBackground element however I would suggest setting the alpha to 0 rather than removing the view with the following:
for (UIView *subview in [[self.searchBar.subviews lastObject] subviews]) {
if ([subview isKindOfClass:NSClassFromString(#"UISearchBarBackground")]) {
[subview setAlpha:0.0];
break;
}
}
Add the above code to your UIViewController subclass that contains an IBOutlet *searchBar. This code snippet will acheive a transparent background for both iOS8 and iOS9.
In addition it may be better design decision to include this code in your UISearchBar subclass in order to avoid cluttering your viewController.
For anyone trying to find a non hacky solution to this, just set the background image to nil on your Storyboard/Xib file. Literally, simply write nil in the background image field of the UISearchBar.
If you want to change this...
To this...
Use:
self.searchBar.searchTextField.backgroundColor = .clear
Simply use searchBar.searchBarStyle = .minimal works for me.
I had used many workarounds for a long time, until i discover this property accidentally, and works like a charm.
For anyone coming here and not being able to make the remove or alpha solution work for you, make sure you have your searchBar SearchStyle NOT on MINIMALIST. Change it to Default and use any of the codes provided here
For iOS 13+ we can simply use:
searchBar.searchTextField.backgroundColor = .clear
but other solutions like:
searchBar.setSearchFieldBackgroundImage(UIImage(), for: .normal)
searchBar.setBackgroundImage(UIImage(), for: .any, barMetrics: .default)
creates a background on the searchBar which hides the placeholder and doesn't allow to interact with the searchBar. The solution for iOS 12 and below is to use an approach similar to #Get Schwifty.
Setting the backgroundColor and barTintColor did not work me iOS 9+, left me with a black background. However Ruozi solution will work. Here is a swift version of the same code.
for view in _searchBar.subviews.last!.subviews {
if view.isKindOfClass(NSClassFromString("UISearchBarBackground")!) {
view.removeFromSuperview()
}
}
My solution working on Swift 4.1 | iOS 11.4 where I change the background and text colors of UISearchBar
The key is to find the UISearchBar's UITextField component and to change its parameters:
let searchTextField = searchBar.value(forKey: "searchField") as? UITextField
searchTextField?.textColor = UIColor.white
searchTextField?.backgroundColor = UIColor.red
searchTextField?.attributedPlaceholder = NSAttributedString(string: "Your Placeholder", attributes: [NSAttributedStringKey.foregroundColor: UIColor.white.withAlphaComponent(0.5)])
Then I set the "search" and the "clear" image
//search image
searchBar.setImage(UIImage(named: "icon_search"), for: UISearchBarIcon.search, state: .normal)
//clear image
searchBar.setImage(UIImage(named: "icon_search_clear"), for: UISearchBarIcon.clear, state: .normal)
extension UISearchBar {
func changeSearchBarColor(fieldColor: UIColor, backColor: UIColor, borderColor: UIColor?) {
UIGraphicsBeginImageContext(bounds.size)
backColor.setFill()
UIBezierPath(rect: bounds).fill()
setBackgroundImage(UIGraphicsGetImageFromCurrentImageContext()!, for: UIBarPosition.any, barMetrics: .default)
let newBounds = bounds.insetBy(dx: 0, dy: 8)
fieldColor.setFill()
let path = UIBezierPath(roundedRect: newBounds, cornerRadius: newBounds.height / 2)
if let borderColor = borderColor {
borderColor.setStroke()
path.lineWidth = 1 / UIScreen.main.scale
path.stroke()
}
path.fill()
setSearchFieldBackgroundImage(UIGraphicsGetImageFromCurrentImageContext()!, for: UIControlState.normal)
UIGraphicsEndImageContext()
}
}
Subclass the uisearchbar and override initWithFrame and initWithCoder method and set the background color as
// For searchbar created programmatically
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
[self configureSetup];
}
return self;
}
// For search bar created on xib
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self configureSetup];
}
return self;
}
- (void)configureSetup
{
self.backgroundColor = [UIColor clearColor];
}
and use the subclassed searchbar instead in place where you specified UISearchBar
Oh man! I've been looking everywhere for a solution and trying multiple things. As #gmogames had mentoned above you can use any of these answers, but make sure the Search Bar Style is set to default or it won't work. So, to clarify on the solution this is what worked for me:
Set Search Bar Style to default in the Storyboard or code(wherever you created the UISearchBar.
Then add this code to your view controller:
mySearchBar.searchTextField.backgroundColor = .clear
For iOS 12, swift 4.x
A bit too hacky but Debug view hierarchy shows _UISearchBarSearchFieldBackgroundView is responsible to the background color. To get to it, ...
for subview in searchBar.subviews.last!.subviews {
if subview.isKind(of: NSClassFromString("UISearchBarTextField")!) {
for v in subview.subviews {
if v.isKind(of: NSClassFromString("_UISearchBarSearchFieldBackgroundView")!) {
v.removeFromSuperview()
}
}
}
}
This is all too hacky. I prefer asking designer to accept Apple default color.
searchBarStyle = .default
searchTextField.backgroundColor = .yourColor
With this combination, you can remove the gray background of searchTextField and set yours!
I tried #Johnson's answer however it didn't work well for me. (iOS 13, swift 5)
However the logic behind the solution seemed well. So tried to iterate all subviews of the searchBar and it worked!
I hope, it will help :)
Solution also worked for me in iOS 12.4 - swift 5
Remove Background Method
private func removeBackground(from searchBar: UISearchBar) {
guard let BackgroundType = NSClassFromString("_UISearchBarSearchFieldBackgroundView") else { return }
for v in searchBar.allSubViewsOf(type: UIView.self) where v.isKind(of: BackgroundType){
v.removeFromSuperview()
}
}
Helper Methods -> UIViewExtension
extension UIView {
public func allSubViewsOf<T : UIView>(type : T.Type) -> [T]{
var all = [T]()
func getSubview(view: UIView) {
if let wrapped = view as? T, wrapped != self{
all.append(wrapped)
}
guard view.subviews.count>0 else { return }
view.subviews.forEach{ getSubview(view: $0) }
}
getSubview(view: self)
return all
}
}
Swift 5.4, iOS 14.5.
Here is the default UISearchBar, on top of a white background:
And the same setup on top of a grey background:
To make the background of the search bar clear, set the search bar style to minimal. This removes the search bar's background and makes the search field translucent.
searchBar.searchBarStyle = .minimal
Then, set the search text field's background color to whatever you want. In this case, I've set it to white.
searchBar.searchTextField.backgroundColor = .white
You can see the result of this here:
If you set searchBar.searchTextField.backgroundColor = .red: