Reputation: 149
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UISearchBarDelegate {
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var searchBar: UISearchBar!
var filteredStates = [State]()
var states = [
State(stateName: "Alabama", abbreviation: "AL" ),
State(stateName: "Alaska", abbreviation: "AK" ),
State(stateName: "Arizona", abbreviation: "AZ"),
State(stateName: "Arkansas", abbreviation: "AR"),
State(stateName: "California", abbreviation: "CA"),
State(stateName: "Colorado", abbreviation: "CO"),
State(stateName: "Connecticut", abbreviation: "CT"),
]
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
searchBar.delegate = self
filteredStates = states
let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap))
tableView.addGestureRecognizer(tap)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableCell", for: indexPath) as UITableViewCell
let state = states[indexPath.row]
cell.textLabel?.text = state.stateName
cell.detailTextLabel?.text = state.abbreviation
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredStates.count
}
// This method updates filteredData based on the text in the Search Box
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
filteredStates = searchText.isEmpty ? states : states.filter { (item: State) -> Bool in
return item.stateName.range(of: searchText, options: .caseInsensitive, range: nil, locale: nil) != nil
}
print(filteredStates)
tableView.reloadData()
}
// Wehn search bar being editing, cancel button pops up
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
self.searchBar.showsCancelButton = true
}
// When search bar cancel button clicked
// Cancel button dismiss, search text is empty, keyboard dismiss
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchBar.showsCancelButton = false
searchBar.text = ""
searchBar.resignFirstResponder()
}
// when click outside of keyboard
// Keyboard dismiss
func handleTap() {
self.view.endEditing(true)
}
// When clicked search button
// keyboard dismiss
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
searchBar.resignFirstResponder()
}
}
My filter is not working correctly. Not sure where I did wrong. I think it might be something wrong with function searchBar function.
The filter is not working correct
The filter is not working correct2
Upvotes: 0
Views: 993
Reputation: 72410
I have slightly changed your code, and with filter
used contains and made some changes in delegate method of UISearchBar and used filteredStates
with all the method of UITableViewDataSource
.
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate {
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var searchBar: UISearchBar!
var filteredStates = [State]()
var states = [
State(stateName: "Alabama", abbreviation: "AL" ),
State(stateName: "Alaska", abbreviation: "AK" ),
State(stateName: "Arizona", abbreviation: "AZ"),
State(stateName: "Arkansas", abbreviation: "AR"),
State(stateName: "California", abbreviation: "CA"),
State(stateName: "Colorado", abbreviation: "CO"),
State(stateName: "Connecticut", abbreviation: "CT"),
]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
filteredStates = states
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredStates.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableCell")!
//Access data from filteredStates array not from states array
cell.textLabel?.text = self.filteredStates[indexPath.row].stateName
cell.detailTextLabel?.text = self.filteredStates[indexPath.row].abbreviation
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print(self.filteredStates[indexPath.row].stateName)
}
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
searchBar.showsCancelButton = true
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
self.filteredStates = searchText.isEmpty ? states : states.filter( { $0.stateName.localizedCaseInsensitiveContains(searchText) })
self.tableView.reloadData()
}
func searchBarBookmarkButtonClicked(_ searchBar: UISearchBar) {
searchBar.resignFirstResponder()
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchBar.resignFirstResponder()
searchBar.showsCancelButton = false
searchBar.text = ""
self.filteredStates = states
self.tableView.reloadData()
}
}
Note: I haven't added code that you are using with TapGesture
so don't forgot to add that.
Upvotes: 1
Reputation: 9923
Create another array to store the searched value
Implement filter logic on your searchBar: textDidChange
method
Create a Bool (eg. isActive
) to indicate if the search happened or cancelled on searchBarShouldBeginEditing
and searchBarCancelButtonClicked
On your cellForRow
, you can check for the Bool isActive
to switch the let state = states[indexPath.row]
to let state = filteredStates[indexPath.row]
Upvotes: 0