I have UICollectionView. On clicking search button in UINavigationBar, I am adding the UISearchController's searchbar as titleview for UINavigationItem. For iPhone it is working properly. For iPad the cancel button is not shown. The Searchbar alone takes the entire width.
Can anyone help me out on this?. Thanks in advance.
iOS7 does not show the cancel button when added to a navigation bar.You can put searchbar in another view like this.
UISearchBar *searchBar = [UISearchBar new];
searchBar.showsCancelButton = YES;
[searchBar sizeToFit];
UIView *viewForSearchBar = [[UIView alloc]initWithFrame:searchBar.bounds];
[viewForSearchBar addSubview:searchBar];
self.navigationItem.titleView = viewForSearchBar;
I had the same problem, on iPhone the search cancel was shown well, but on iPad it didn't.
The workaround of wrapping the UISearchBar in another UIView didn't work well for me since it had different appearance and wrong width on rotation.
My solution is a simple one - use search WITHOUT cancel, and add cancel as a UIBarButtonItem.
Added rightBarButtonItem with selector will work fine for me. And adding searchBar inside view before setting to navigation title view was not showing properly.
Code:-
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.plain, target: self, action: #selector(self.dismissView))
func dismissView() {
if self.controller?.navigationController?.popViewController(animated: true) == nil {
self.controller?.dismiss(animated: true, completion: nil)
}
}
As per apple documentation setShowsCancelButton
Cancel buttons are not displayed for apps running on iPad, even when
you specify YES for the showsCancelButton parameter.
I am not sure about the alternate but this is what apple provides us.
Try this. Add a checkmark for shows cancel button.
Swift version :-
I tried the #Nikita Khandelwal method, but still it doesn't fit for ipad view. Here is the swift code, which was given as corrected answer :-
let searchBar: UISearchBar = UISearchBar()
searchBar.showCancelButton = true
searchBar.placeholder = "Search Your Job Title"
searchBar.fitToSize()
searchBar.delegate = self //do not need if you delegate searchBar
let viewForSearchBar: UIView = UIView(frame: searchBar.bounds)
viewForSearchBar.addSubview(searchBar)
self.navigationItem.titleView = viewForSearchBar
********* But There is another way to set cancel button correctly and fit for the view :-
Set search bar as the Navigation bar title view :-
let searchBar: UISearchBar = UISearchBar()
searchBar.showCancelButton = true
searchBar.placeholder = "Search Your Job Title"
searchBar.delegate = self //do not need if you delegate searchBar
self.navigationItem.titleView = searchBar
Drag and drop Bar button to the right side of the view controller & name it as Cancel.
Then connect that button to this function :-
#IBAction func iPadCancelButton(sender: AnyObject) {
UIApplication.sharedApplication().sendAction("resignFirstResponder", to:nil, from:nil, forEvent:nil)
self.dismissViewControllerAnimated(true, completion: nil)
}
For iOS 13 built with Xcode 11, I'm needing to set manually set the display value on the cancel button, depending on whether the search controller is visible
Related
I'm a beginner in swift and trying to learn UIPickerView which has done button to close after the selection from the picker view. I have following code to add the tool bar and the done button to the picker as a toolbar in subview. It shows up as a blank black toolbar (attached screenshot)
let toolBar = UIToolbar()
toolBar.barStyle = .black
toolBar.sizeToFit()
let doneBtn = UIBarButtonItem.init(title: "Done", style: .plain, target: self, action: #selector(self.closePicker))
toolBar.items = [doneBtn]
toolBar.isUserInteractionEnabled = true
picker.addSubview(toolBar)
Picker is the outlet for UIPickerView in my controller. What am I doing wrong? I referred to other questions but they dont seem to solve my problem. Any suggestions?
You are wrong at this line:
picker.addSubview(toolBar)
Picker is not supposed to have any subviews - it's a comprehensive view by itself and there is no area in it to accommodate anything in addition.
Instead you need to add both the picker and the toolbar on the same view and align them next to each other
let toolBar = UIToolbar()
...configure your toolbar here...
guard let superview = picker.superview else { return }
superview.addSubview(toolBar)
toolBar.translateAutoresizingMaskIntoConstraints = false
NSLayoutConstraints.activate([
toolBar.topAnchor.constraint(equalTo: superview.topAnchor),
toolBar.leftAnchor.constraint(equalTo: superview.leftAnchor),
toolBar.rightAnchor.constraint(equalTo: superview.rightAnchor),
toolBar.bottomAnchor.constraint(equalTo: picker.topAnchor)
])
You should not add toolBar as subView of picker.
You should set the toolBar as inputAccessoryView of textField.
As I searched for this problem I got that the common way (also easiest way) to achieve what you want is Using dummy textField.
It means create a textField at the exact frame of button and hide it, when user touches the button make the textField firstResponder.
#IBAction func pickerButtonClicked(_ sender: Any) {
self.pickerViewTextField.becomeFirstResponder
}
I am unable to add a tool bar to my tableView using the Xcode main.storyboard.
Thus, I tried coding it in manually in the viewDidLoad()
let logOutButton = UIBarButtonItem(title: "Log Out", style: UIBarButtonItemStyle.Bordered, target: self, action: "logOut")
var bottomBarButtonArray = [UIBarButtonItem]()
bottomBarButtonArray.append(logOutButton)
self.navigationController!.setToolbarHidden(false, animated: true)
self.navigationController!.toolbar.items = bottomBarButtonArray
May I know how do I set the logOutButton text and also how to detect if logOutButton has been pressed.
I tried logOutButton.description = "Log Out" but it does not work.
My toolbar does appear but I have no idea how to add the text for the logout button.
The solution is to use UIViewController as parent class and not UITableViewController
How to add a toolbar to a TableView in iOS
If the TableView happens to be embedded in a Navigation Controller, there is an easy solution: you can add the Toolbar straight away in the NavigationController. The checkbox 'Shows Toolbar' in the Attributes Inspector is all you need.
Details: https://stackoverflow.com/a/34832688/5897915
In my app, I used to have a search bar in the header view of my table view. However, I have added a search bar button item, and when a user taps it, I want a search bar to animate across the navigation bar, and the user should be able to search. This is kind of like the search bar in the Twitter iOS app. here is the code for my UISearchController:
self.searchController = ({
let controller = UISearchController(searchResultsController: nil)
controller.searchResultsUpdater = self
controller.hidesNavigationBarDuringPresentation = true
controller.dimsBackgroundDuringPresentation = false
controller.searchBar.sizeToFit()
//self.tableView.tableHeaderView = controller.searchBar
self.definesPresentationContext = true
controller.searchBar.returnKeyType = .Search
controller.searchBar.delegate = self
return controller
})()
Here is how my UINavigationBar looks like right now:
How would I go about doing this?
You're almost there. You need to do four things:
searchController.hidesNavigationBarDuringPresentation = false
navigationItem.titleView = searchController.searchBar
hide all the current UIBarButtonItems you have in the navigation bar
searchController.searchBar.becomesFirstResponder()
That is, you setup your UISearchController so it doesn't hide the navigation bar, as the UISearchBar is gonna be displayed there.
Then, when your IBAction runs, you do something like:
navigationItem.hidesBackButton = true
navigationItem.titleView = searchController.searchBar
navigationItem.rightBarButtonItem = nil
searchController.searchBar.becomeFirstResponder()
That guarantees the UISearchBar will use the entire UINavigationBar when it becomes the first responder. You also get the UISearchBar animation, which does a good job in hiding the unanimated removal of the UIBarButtonItems.
You will need to implement the UISearchBarDelegate (or if you prefer UISearchControllerDelegate) to restore the original navigation bar state once the user is done with the search.
One very important detail is that in order for your UISearchBar to be editable in the titleView, no other view controller can be set with definesPresentationContext = true at the time yours is pushed.
Notice how the searchBar magnifying glass and placeholder text both shift over on dismissal:
Is there any way I could dismiss this search bar without the text and icon moving over? See the animation of the Music app for the animation I am trying to achieve.
I have a UISeachBar that gets presented when the search button is clicked in a nav bar.
#IBAction func searchButtonPressed(sender: AnyObject) {
searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.searchBar.delegate = self
searchController.hidesNavigationBarDuringPresentation = false
searchController.dimsBackgroundDuringPresentation = false
presentViewController(searchController, animated: true, completion: nil)
}
Now when the cancel button is pressed, I want the whole view to move up without seeing the SearchBar icon and placeholder text slide to the center of the searchBar as the view moves up off screen.
I know there is the method searchBarCancelButtonClicked(searchBar:), but this seems to automatically dismiss the SearchBar and I don't know how to control that.
How can I make the SearchBar dismiss like the one in the Music app?
EDIT: Here is the only delegate method I am using:
func updateSearchResultsForSearchController(searchController: UISearchController) {
masterFilter.removeAll()
filterContentForSearchText(searchController.searchBar.text!)
tableView.reloadData()
}
This is how I have achieved this. It is simple and easy.
extension UIViewController {
func setNavigationBarItem() {
let searchaButton = UIButton.init(frame: CGRectMake(0, 0, 30, 30))
searchaButton.setBackgroundImage(UIImage(named: "search.png"), forState: UIControlState.Normal)
searchaButton.addTarget(self, action: #selector(self.searchPressed), forControlEvents: UIControlEvents.TouchUpInside)
let rightButton: UIBarButtonItem = UIBarButtonItem.init(customView: searchaButton)
navigationItem.rightBarButtonItem = rightButton
}
public func searchPressed(){
var searchController: UISearchController!
// Create the search results view controller and use it for the UISearchController.
let searchResultsController = storyboard!.instantiateViewControllerWithIdentifier("SearchResultController") as! SearchResultsViewController
// Create the search controller and make it perform the results updating.
searchController = UISearchController(searchResultsController: searchResultsController)
searchController.searchResultsUpdater = searchResultsController
searchController.hidesNavigationBarDuringPresentation = false
// Present the view controller.
presentViewController(searchController, animated: true, completion: nil)
}
}
Note:
This code is for old swift version.
I hope this will help you.
The searchBar expands to the right because the search is being cancelled, and the cancel button is disappearing.
Instead of canceling the search and triggering that animation, simply explicitly dismiss the search controller.
You can do this by setting
searchController.active = false
To make this animation work, you'll need to understand custom UIViewController transitions. Within the UISearchBarDelegate method -searchBarCancelButtonClicked(searchBar:), you'll need to do a few things:
Hide the UINavigationBar on the UISearchController dismissal
Animate the UITableView to the bottom of the frame and fade out.
If you're presenting search modally, ensure that you're setting the modalPresentationStyle to UIModalPresentationCurrentContext.
So, I am currently trying to replace the depricated searchDisplayController in one of my projects with UISearchController and I am running into this problem.
If there are no results in the search (the UITableView is empty) the whole ViewController is dismissed. This does not happen when the search results are not empty. I wan't to make it clear I am not using a UITableViewController. Instead I have a regular VC with a UITableView in it.
Here is some of my code:
var resultSearchController = UISearchController()
override func viewDidLoad() {
super.viewDidLoad()
self.resultSearchController = ({
let controller = UISearchController(searchResultsController: nil)
controller.searchResultsUpdater = self
controller.dimsBackgroundDuringPresentation = false
controller.searchBar.sizeToFit()
controller.delegate = self
controller.searchBar.delegate = self
self.studentTable.tableHeaderView = controller.searchBar
return controller
})()
....
}
Now, if I add this function to the equation the cancel button always dismisses the VC.
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
resultSearchController.active = false
}
So why exactly does setting the searchController.active = false dismiss the VC? Is it because it is using the same UITableView as the VC? I believe that the old searchDisplayController would just display a UITableView over the one being used. If this is the case is there a way to override the dismissVC?
this is also Happening to me. The Way I Solve it is by Replacing:
resultSearchController.active = false
with
resultSearchController.searchBar.text = ""
resultSearchController.searchBar.resignFirstResponder()
I Hope this helps you :-)
2018 Just wanna share the fruits of my 1-2 hours debugging.
I had multiple issues with using UISearchController with UITabBarController, namely:
This one, this very question of the OP. Hitting cancel button dismisses the screen that is presenting the searchController.
The tab (or the screen) becomes black, Tab Bar and UISearchController giving black screen
Using UISearchController inside the title view of the navigation bar of UINavigationController in both iOS 10, 11, and 12, like this questions. UISearchBar increases navigation bar height in iOS 11
And for the solution for #3, since we're already here: https://stackoverflow.com/a/53264329/3231194
Finally, the ONLY solution that I have been seeing all this time is adding this code:
self.definesPresentationContext = true
The issue is that I was putting this in a wrong function.
Remember, that solution solved the #1, and #2 problem that I had. Nothing more, nothing less.
Where to add that? Inside the viewDidAppear. That's it!