Поиск ячеек UITableView, используя текст UISearchBar - PullRequest
0 голосов
/ 12 апреля 2019

Я хочу показать отфильтрованные ячейки в UITableView, используя UISearchBar, но он не работает. Моя функция поиска находится в конце моего кода.


import UIKit

struct User2: Codable {
    let firstName: String
    let lastName: String
    let email: String
    let userid: String

    enum CodingKeys: String, CodingKey {
        case firstName = "first_name"
        case lastName = "last_name"
        case email = "email"
        case userid = "user_id"
    }
}

class SearchViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    @IBOutlet weak var tableview: UITableView!

    @IBOutlet var searchBtn: UISearchBar!
    private var dataSource = [User]() {
        didSet {
            self.tableview.reloadData()
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        self.tableview.register(UITableViewCell.self, forCellReuseIdentifier: "groupCell")
        self.tableview.dataSource = self
        self.tableview.delegate = self

        let url = URL(string: "https://ex.com/ex.php")

        URLSession.shared.dataTask(with: url!, completionHandler: { [weak self] (data, response, error) in
            guard let data = data, error == nil else {
                print(error?.localizedDescription ?? "An error occurred")
                return
            }

            DispatchQueue.main.async {
                self?.dataSource = try! JSONDecoder().decode([User].self, from: data)
            }
        }).resume()
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        tableview.reloadData()
    }

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return dataSource.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "groupCell", for: indexPath)
        let user = self.dataSource[indexPath.row]
        cell.textLabel?.text =  user.firstName + " " + user.lastName

        return cell
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let user = self.dataSource[indexPath.row]
        let userVC = DataViewController(user: user)
        self.navigationController?.pushViewController(userVC, animated: true)
    }
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        User2 = User2.filter({ (item) -> Bool in
            let heading: NSString = ((item["firstName"]! as? String)! + (item["lastName"]! as! String)) as NSString
            return (heading.range(of: searchText, options: NSString.CompareOptions.caseInsensitive).location) != NSNotFound
        })
        self.tableview.reloadData()
    }

}

Ответы [ 3 ]

1 голос
/ 12 апреля 2019

Лучшим подходом было бы иметь 2 источника данных, один для нормального состояния, другой при активном поиске, например:

class SearchViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    private var dataSource = [User]() {
        didSet {
            self.tableview.reloadData()
        }
    }

    private var searchDataSource: [User]? {
        didSet {
            self.tableView.reloadData()
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        ...
        self.searchBtn.delegate = self
    }

    // some changes to UITableView DataSource/Delegate
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.searchDataSource?.count ?? self.dataSource.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        ...
        let user = self.searchDataSource?[indexPath.row] ?? self.dataSource[indexPath.row]
        ...
     }

}

Наконец, используйте следующее расширение, расширяющее UISearchBarDelegate

extension SearchViewController: UISearchBarDelegate {

    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        if searchText.isEmpty {
            self.searchDataSource = nil
        } else {
            self.searchDataSource = self.dataSource.filter({
                let fullName = $0.firstName + " " + $0.lastName
                return fullName.range(of: searchText, options: [.anchored, .caseInsensitive]) != nil
            })
        }
    }

    func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
        if self.searchDataSource != nil && searchBar.text?.isEmpty ?? true {
            self.searchDataSource = nil
        }
    }

}

, что дает

enter image description here

0 голосов
/ 12 апреля 2019

Вы можете попробовать применить фильтрацию в вашем dataSource как:

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
   let filteredArray = dataSource.filter({ user in
   let username = "\(user.firstName) \(user.lastName)"
      return username.range(of: searchText, options: .caseInsensitive) != nil
   })
   self.tableview.reloadData()
}
0 голосов
/ 12 апреля 2019

Я думаю, что фильтр должен применяться к dataSource as, где dataSource имеет вид [User2]:

    let filteredArr: [User] = dataSource.filter({ $0.firstName.lowercased().contains(searchText.lowercased()) || $0.lastName.lowercased().contains(searchText.lowercased()) })
...