Below Gif is from my app, the 1st VC includes a search bar to filter the songs, and when press a row to transition to 2nd VC to show selected playing song.
The question here is that when 2nd VC is opened, the search bar is not disappeared immediately, it has like 1 or 2 seconds delay, could see that behavior from below GIF.
/ / / Here is my code, how could I solve this issue? Any hint is appreciate.
The search bar
var resultSearchController = UISearchController()
override func viewDidLoad() {
...
// add search bar
resultSearchController = ({
let controller = UISearchController(searchResultsController: nil)
controller.searchResultsUpdater = self
controller.hidesNavigationBarDuringPresentation = false
controller.dimsBackgroundDuringPresentation = false
controller.searchBar.sizeToFit()
// set search Bar covered color, same with tableView's background color.
controller.searchBar.barTintColor = UIColor(rgb: 0x292f33)
self.tableView.tableHeaderView = controller.searchBar
return controller
})() // closure, learn it later!!
...
}
I set search bar to disabled state when leaving current VC.
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(true)
resultSearchController.isActive = false
}
/ / / Update, as matt's comment, I change the code to integrate search bar into navigation bar, and now the search bar is disappear immediately after opening VC2.
remove self.tableView.tableHeaderView = controller.searchBar and integrate the search bar into the nav bar navigationItem.searchController = resultSearchController. Now the behavior is same as Apple's inbox app.
searchController.searchBar.isHidden = false
Hiding the searchController instead of making the active state to false may solve your issue.
Try adding in the above line to your code in viewWillDisappear()
hopefully this helps.
Related
I'm trying to present a search controller in response to a button, by setting its isActive property, but it doesn't appear.
lazy var searchController: UISeachController = {
let searchController = UISearchController(searchResultsController: nil)
searchController.delegate = self
return searchController
}()
override func viewDidLoad() {
super.viewDidLoad()
definesPresentationContext = true
}
// Called when a button on the navbar is tapped
#obcj private func searchTapped() {
// The doc says you can force the search controller to appear by setting isActive,
// but nothing happens
searchController.isActive = true
// Calling present does show it, but the search bar appears behind the navbar.
// And the delegate methods are still not called
//present(searchController, animated: true)
}
func willPresentSearchController(_ searchController: UISearchController) {
// Not called, even when calling 'present'
}
It seems isActive only works if the search bar is in the view hierarchy.
// This will place the search bar in the title view, allowing you to
// have other buttons on the right of the search bar.
navigationItem.titleView = searchController.searchBar
Or
// This takes up a whole other row under title row.
navigationItem.searchController = searchController
But if you go this route, you don't need to set isActive yourself - the search controller automatically comes up when the user interacts with the search bar. I still don't understand how isActive is supposed to be used, but it does answer the original question.
I need to show large navigation title while search with searchBar, but when I'm clicking on Searchbar or starting to type my NavigationTitle is replaced with SearchBar. I checked methods for navigationItem and didn't find any suitable.
Does anybody know how can we always show title, even while searching?
Here is my code
class FavouriteVC: UIViewController {
let searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.title = "Favourite"
navigationItem.searchController = searchController
navigationItem.largeTitleDisplayMode = .always
}
}
And here are shots
screen with NavTitle
screen without NavTitle
Seems like UISearchController has a hidesNavigationBarDuringPresentation that prevents the navigation bar from hiding when set to false
Include:
searchController.hidesNavigationBarDuringPresentation = false
in your viewDidLoad and if I've understood your issue right, this should do what you need.
I have a navigation bar which includes a search bar to filter the table data in current VC, let's call it 1st VC.
And the steps is active this search bar and cancel it. Then click any row of tableView 1st VC to open 2nd VC. The weird behavior is coming, the navigation title of 2nd VC is overlapped with 1st VC's nav title. Also the button on top-right is not clickable anymore after this issue happened. I get this when upgrade to iOS 13 from previous version 12.
/ / / attach the issue screenshot firstly, you could see that title "Music" in 1st VC is overlapped with title "Playing" in 2nd VC.
/ / / nav bar code in 1st VC
override func viewDidLoad() {
super.viewDidLoad()
// set tableView's separatorColor
self.tableView.separatorColor = UIColor(rgb: 0x5E5E5E)
// get songs from app's local dir
self.retrieveSongsfromLocalDir()
// add search bar
resultSearchController = ({
let controller = UISearchController(searchResultsController: nil)
controller.searchResultsUpdater = self
controller.hidesNavigationBarDuringPresentation = false
controller.obscuresBackgroundDuringPresentation = false
controller.searchBar.sizeToFit()
// set search Bar covered color, same with tableView's background color.
controller.searchBar.barTintColor = UIColor(rgb: 0x292f33)
return controller
})() // closure, learn it later!!
navigationItem.searchController = resultSearchController
// reload the tableView
self.tableView.reloadData()
}
/ / / I put the custom code of navigation bar in AppDelegate.swift for global use.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Custom Navigation Bar's appearance.
UINavigationBar.appearance().tintColor = UIColor.white
UINavigationBar.appearance().barTintColor = UIColor(rgb: 0x55acee)
UINavigationBar.appearance().isTranslucent = false
UINavigationBar.appearance().clipsToBounds = false
// UINavigationBar.appearance().backgroundColor
UINavigationBar.appearance().titleTextAttributes = [.foregroundColor: UIColor.white, .font: UIFont.boldSystemFont(ofSize: 23)]
return true
}
/ / / Update, it is duplicate with thread https://stackoverflow.com/questions/58134631/ios-13-uibarbuttonitem-not-clickable-and-overlapping-uinavigationbars-when-using. It seems the bug of Apple from iOS 13, and temporary fix is to set hidesNavigationBarDuringPresentation = true.
So on my first vc I have set the nav bar to a large title. Then I have a button which goes to a vc with a nav bar with a small title.
When I go back from my second vc to the first, it displays the small title for a bit then jumps down to the large title.
Here is my code in the first vc bc its a tab view controller:
override func viewWillAppear(_ animated: Bool) {
self.navigationController?.navigationBar.prefersLargeTitles = true
}
Here is the code for the second vc in the viewDidLoad():
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedString.Key.font: UIFont(name: "Avenir-Black", size: 20)!]
self.navigationController?.navigationBar.prefersLargeTitles = false
This is what I mean about the jumpy transition
Thanks
On your second ViewController Try changing the NavBarPreference inside viewWillDisappear function.
Example:
func viewWillDisappear(_ animated: Bool){
self.navigationController?.navigationBar.prefersLargeTitles = true
}
So before going back to the first vc you change the NavBar preference first
Alternative Solution: Using Storyboard
You can click on the desired VC then click on its navBarItem then go to your right to properties and on Large Title Select Never, Always or Automatic from the dropdown list.
Example
Short answer is to not rely on largeTitleDisplayMode = .automatic (the default value) and prefersLargeTitles = true/false but instead to be explicitly setting .always or .never with prefersLargeTitles = true (yes even when using never).
You need to always have prefersLargeTitles to be true because of this from Apple doc:
If the prefersLargeTitles property of the navigation bar is false, this property has no effect and the navigation item’s title is always displayed as a small title.
This is an issue you have on iOS11/12 but on iOS13 it will be surfaced a bit differently.
i have a UICollectionViewController where i am showing list of task which is working fine, recently i tried to implement a UISearchBar for my TaskController after implementing that, when i try to launch any new viewcontroller by clicking on row inside my TaskController the newly launched view controller does not have UINavigationBar so i cant move back to my task list again. see following TaskController with task list:
Image
in above screen shot there is a star icon when user click on that, I launch following view controller which have a navigation bar(note: I have click directly without filtering records thats why i can see the navigation bar here.). UIViewController with UINavigationBar
Image
this is what i get when i click on star icon after filtering data with search bar.
navigation bar gone missing here
so i can not go back to task list controller also when i change a tab from below and come back the view controller got destroyed and i get a black screen with tab bar.
following code i have used to implement search bar which have the problem please help me to figure it out.
let taskSearchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
//set taskSearchController
taskSearchController.searchResultsUpdater = self
taskSearchController.dimsBackgroundDuringPresentation = false
navigationItem.searchController = taskSearchController
getTaskList(){
}
}
following method gives the filtered data from tasklist
func updateSearchResults(for searchController: UISearchController) {
guard let searchText = searchController.searchBar.text, !searchText.isEmpty else{
self.taskList = self.originalTaskist
collectionView?.reloadData()
return
}
taskList = originalTaskist.filter({ task -> Bool in
return task.name!.lowercased().contains(searchText.lowercased())
})
collectionView?.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
// This prevents the search bar to make trouble on pushed view controllers
definesPresentationContext = true
//...
}
Put definesPresentationContext = true inside of your View Controller that shows the search bar (the UICollectionViewController in your case.
Unfortunately, the documentation doesn't explain very well why this is working. This blog post explains it a little better.