Reputation: 829
I'm trying to implement Tableview multiple selections and search at the same time. The multiple selection is easy but I but I want the cells to stay selected when searching.
I can't find any example that implements both at the same time so if you have any examples or sample projects that I can look at, please feel free to share!
Here's my code:
class InviteVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
var tableView: UITableView!
var phoneContacts = [PhoneContact]()
var selectedContacts = [PhoneContact]()
var filteredContacts = [PhoneContact]()
var rowToSelect = IndexPath(row: 0, section: 0)
var recipients = [String]()
var filter: ContactsFilter = .none
let searchController = UISearchController(searchResultsController: nil)
func filterContentForSearchText(_ searchText: String) {
filteredContacts = phoneContacts.filter({( contact : PhoneContact) -> Bool in
return contact.name!.lowercased().contains(searchText.lowercased())
})
tableView.reloadData()
}
}
extension InviteVC {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if isFiltering() {
return filteredContacts.count
}
return phoneContacts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "ContactCell", for: indexPath) as? ContactCell {
let contact: PhoneContact
if isFiltering() {
contact = self.filteredContacts[indexPath.row]
} else {
contact = self.phoneContacts[indexPath.row]
}
cell.configure(contact)
return cell
}
return UITableViewCell()
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! ContactCell
cell.isSelected = true
let contact: PhoneContact
if isFiltering() {
contact = self.filteredContacts[indexPath.row]
} else {
contact = self.phoneContacts[indexPath.row]
}
self.selectedContacts.insert(contact, at: 0)
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! ContactCell
}
extension InviteVC: UISearchBarDelegate {
// MARK: - UISearchBar Delegate
func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
filterContentForSearchText(searchBar.text!)
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
self.selectedContacts.removeAll()
if let selectedItems = tableView.indexPathsForSelectedRows {
for item in selectedItems {
tableView.deselectRow(at: item, animated: true)
let cell = tableView.cellForRow(at: item) as! ContactCell
cell.backgroundColor = .white
tableView.reloadData()
}
}
}
}
extension InviteVC: UISearchResultsUpdating {
// MARK: - UISearchResultsUpdating Delegate
func updateSearchResults(for searchController: UISearchController) {
let searchBar = searchController.searchBar
if let searchText = searchBar.text,
!searchText.isEmpty {
filteredContacts.removeAll()
}
filterContentForSearchText(searchController.searchBar.text!)
}
}
Upvotes: 3
Views: 1267
Reputation: 3821
You shouldn't have to set cell.isSelected = true
in the didSelectRowAt
method. That will be done automatically by the tableview.
The trick to keeping the selection is telling the tableview to select a row after it has reloaded the cells. Probably the best place to put it is in willDisplayCell
.
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let contact = searchController.isActive ? filteredContacts[indexPath.row] : contacts[indexPath.row] //Update as needed
if selectedContacts.contains(contact) {
tableView.selectRow(at: indexPath, animated: false, scrollPosition: .none)
} else {
tableView.deselectRow(at: indexPath, animated: false)
}
Upvotes: 2
Reputation: 11539
Add this to your cellForRowAtIndexPath
method, underneath cell.configure(contact)
:
cell.isSelected = self.selectedContacts.contains(contact)
Upvotes: 0