首页 > 解决方案 > 如何实现 TextField 搜索结果以过滤 tableview 值 Swift

问题描述

我创建了一个 pickerView 来将值选择到 ViewController 顶部的自定义 textField 栏中,以过滤 UITableView 中的数据值。由于我有嵌套类型的 JSON,因此无法正确了解如何使用过滤器。

我想用 TableView 将 textField 实现为搜索栏。附上截图。

我需要过滤的值是 Parkings.Address -> textField

为文本搜索添加了 textFieldDidEndEditing 函数。

模型:

struct JSONDB: Codable {
    var ParkingInfoList: [`Parkings`]
}

struct Parkings: Codable {
    var Id: String
    var Name: String
    var Tel: String
    var CarTotal: String
    var CarRemaining: String
    var Address: String
    var ServiceTime: String
    var ChargeInfo: String
    var ParkinfInfo: String? 
    var Lat: String
    var Lng: String
}
struct JSONDB2: Codable {
    var ParkingCityList: [City]
}

struct City: Codable {
    var CityCode: String
    var CityChtName: String
    var CityArea: [String]
}

JSON数据:

{
  "ParkingInfoList": [
    {
      "Id": "K82",
      "Name": "瑞湖停車場",
      "Tel": "0226573430",
      "Address": "文德段5小段297地號;民權東路6段15巷50號空地",
      "CarTotal": "46",
      "CarRemaining": "暫時無提供資訊",
      "MotorTotal": "暫時無提供資訊",
      "MotorRemaining": "暫時無提供資訊",
      "ServiceTime": "24小時",
      "ChargeInfo": "計次:50元/次,(每次以2.5小時為限)。月租:3,000元/月。",
      "ParkingInfo": "一般平面式小型車46格(含身心障礙停車位2格)。",
      "City": "TPE",
      "Area": "內湖區",
      "Lat": "25.06854351",
      "Lng": "121.5769806",
      "SourceUpdateTime": "2020-09-24T00:00:00"
    },

视图控制器代码:

import UIKit

class SelectedTableViewController: UITableViewController, UIPickerViewDelegate, UIPickerViewDataSource,UITextFieldDelegate {
    
    @IBOutlet weak var myTextfield: UITextField!
    
    let myPickerView = UIPickerView()
    var selectedArea = ""
    
    var loadingData = [City]()
    var parkingData = [Parkings]()
    var okData : Parkings?
    
    var searchActive = false
    var arrfilter = [Parkings]()
    
    

    let apiAddress = "https://lifeinfo.megatime.com.tw/lifeInfo/QueryParkingCityList.ashx"
    let urlSession = URLSession(configuration: .default)
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.myPickerView.delegate = self
        self.myPickerView.dataSource = self
        self.myTextfield.delegate = self
        downloadInfo(withAddress: apiAddress)
        myTextfield.inputView = myPickerView
        myPickerView.showsSelectionIndicator = true
    }
    
    
    func downloadInfo(withAddress webAddress: String ){
        if let url = URL(string: webAddress){
            let task = urlSession.dataTask(with: url) { (data, response, error) in
                if error != nil{
                    let errorcode = (error! as NSError).code
                    if errorcode == -1009{
                        print("No Internet Connection")
                    }else{
                        print("Something Wrong")
                    }
                    return
                }
                if let loadedData = data{
                    print("Got Data")
                    do{
                        let decoder = JSONDecoder()
                        let JSONdb = try decoder.decode(JSONDB2.self, from: loadedData)
                        print("JSONDB2 OK")
                        self.loadingData = JSONdb.ParkingCityList
                        DispatchQueue.main.async {
                            
                            self.tableView.reloadData()
                        }
                    }catch{
                        print(error)
                    }
                    
                }
            }
            task.resume()
        }
    }
    
    func initPickerView(touchAt sender:UITextField){
        let toolBar = UIToolbar()
        toolBar.barStyle = UIBarStyle.default
        toolBar.isTranslucent = true
        toolBar.tintColor = .systemBlue
        toolBar.sizeToFit()
        let doneButton = UIBarButtonItem(title: "check", style: .plain, target: self, action: #selector(submit))
        let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
        let cancelButton = UIBarButtonItem(title: "cancel", style: .plain, target: self, action: #selector(cancel))
        toolBar.setItems([cancelButton, spaceButton, doneButton], animated: false)
        toolBar.isUserInteractionEnabled = true
        myTextfield.inputAccessoryView = toolBar
        myTextfield.inputView = myPickerView
    }
    
    @objc func cancel(){
        self.myTextfield?.resignFirstResponder()
    }
    @objc func submit(sender: UIBarButtonItem){
        DispatchQueue.main.async { [self] in
            self.myTextfield.text = "taipei \(self.selectedArea)"
            self.myTextfield?.resignFirstResponder()
        }
    }
    
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        2
    }
    
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        if component == 0{
            return 1
        }
        return loadingData[0].CityArea.count
    }
    
    
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        if component == 0{
            return "taipei"
        }
        let test = loadingData[0].CityArea[row]
        // print(test)
        return test
    }
    
    func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
        if textField == self.myTextfield {
            myTextfield.isHidden = false
            myPickerView.removeFromSuperview()
            self.initPickerView(touchAt: textField)
        }
        return true
    }
    
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return true
    }
    

    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        myTextfield.text = "臺北市 \(loadingData[0].CityArea[row])"
        self.selectedArea = loadingData[0].CityArea[row]
    }
   
    
    // MARK: - Table view data source
    
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if myTextfield.text == ""{
            return parkingData.count
            
        }else {
            myTextfield.text = selectedArea
            
        }

        return 1        
    }
  
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "SelectedTableViewCell", for: indexPath) as! SelectedTableViewCell
        let data = parkingData[indexPath.row]
        cell.lbRemaining.text = data.CarRemaining
        cell.lbName.text = data.Name
        
        return cell
    }
    
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        self.okData = self.parkingData[indexPath.row]
        performSegue(withIdentifier: "DetailSegue", sender: self)
        
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "DetailSegue"{
            let detail = segue.destination as! DetailTableViewController
            detail.okData = self.okData
            
            
        }
    }
    
}

下面是我已经尝试过但失败的过滤器部分:

尝试1:谓词方式但显示错误:“无法解析格式字符串“SELF.Address CONTAINTS[C] %@””

尝试2:过滤方式但显示错误:“无法将'Parkings'类型的值转换为强制类型'NSString'”

    func textFieldDidEndEditing(_ textField: UITextField) {
        guard let searchText:String  = myTextfield.text else {
            return}

    \\ try 1: predicate way but show error: "Unable to parse the format string \"SELF.Address CONTAINTS[C] %@\""

        let predicate:NSPredicate = NSPredicate(format: "SELF.Address CONTAINTS[C] %@", searchText)
        let array = (parkingData as NSArray).filtered(using: predicate)
        print("array =\(array)")

    \\ try 2: filter way but show error: "Cannot convert value of type 'Parkings' to type 'NSString' in coercion "

          arrfilter = parkingData.filter({ (test) -> Bool in
          let tmp: NSString = test as NSString
          let range = tmp.range(of: searchText, options: NSString.CompareOptions.caseInsensitive)
          return range.location != NSNotFound
            })

            if(arrfilter.count == 0){
                searchActive = false;
            } else {
                searchActive = true;
            }
             self.tableView.reloadData()
    }
    

最后的礼物应该像这样显示

标签: iosswiftuitableviewuitextfielduipickerview

解决方案


推荐阅读