How to implement TextField search bar to filter tableview values Swift

元气小坏坏 提交于 2020-03-25 22:03:34

问题


I have created a custom textField bar on top of the ViewController to filter data values in UITableView. As I have a nested type of JSON so couldn't properly get how to use filter for it.

  • I want to implement textField as a search bar with TableView. screenshot attached.
  • Value which I need to filter is pickList -> textField
  • textSearchChange function added for text search.

Data is section wise and then values and is already displaying in tableView.

Model:

struct SectionList : Codable {

    let title : String?
    var items : [Item]?

}

struct PickListData: Codable {
    let items: [Item]?
}

struct Item : Codable {

    let actionType : Int?
    var textField : String?
    var pickList: [SectionList]?
    var selection: [Item]?
    let selectedValue: [String]?
    let version: Int?
    let masterId: Int?
    let itemValue: String?
}

ViewController Code:

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet weak var searchTxt: UITextField!
    @IBOutlet weak var tableView: UITableView!
    var AppData: Item?
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        tableView.delegate = self
        tableView.dataSource = self
        searchTxt.delegate = self
        readDataList()
    }
    func readDataList(){

        if let url = Bundle.main.url(forResource: "list", withExtension: "json") {
            do {

                let data = try Data(contentsOf: url)
                let decoder = JSONDecoder()
                let response = try decoder.decode(PickListData.self, from: data)
                let res = response.items?.filter { $0.actionType == 101}
                AppData = res?.first
                print(AppData)
                self.tableView.reloadData()
            } catch {
                print("error:\(error)")
            }
        }

    }

    @IBAction func textSearchChange(_ sender: UITextField) {
        print("search")
    }


}

extension ViewController: UITableViewDelegate, UITableViewDataSource {

    func numberOfSections(in tableView: UITableView) -> Int {
        return AppData?.pickList?.count ?? 0
        }

    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return AppData?.pickList?[section].title
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return AppData?.pickList?[section].items?.count ?? 0
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell()
        let dic = AppData?.pickList?[indexPath.section].items?[indexPath.row]//.pickList?[indexPath.row].title
            //AppData?[indexPath.section].pickList[indexPath.row].items
        //print(dic)

        cell.textLabel?.text = dic?.textField
        return cell
    }

}

JSON Data:

{
  "items": [
    {
      "actionType": 101,
      "version": 3,
      "pickList": [
        {
          "title": "Sayaç yeri seçimi",
          "items": [
            {
              "textField": "Sayaç Yeri Seçiniz",
              "itemValue": "0"
            },
            {
              "textField": "Sayaç daire girişinde",
              "itemValue": "1"
            },
            {
              "textField": "Sayaç apt. girişinde",
              "itemValue": "2"
            },
            {
              "textField": "Sayaç bodrumda",
              "itemValue": "3"
            },
            {
              "textField": "Sayaç çatı katında",
              "itemValue": "4"
            },
            {
              "textField": "Sayaç bahçede (Müstakil)",
              "itemValue": "5"
            },
            {
              "textField": "Sayaç bina dışında",
              "itemValue": "6"
            },
            {
              "textField": "Sayaç balkonda",
              "itemValue": "7"
            },
            {
              "textField": "Sayaç daire içinde",
              "itemValue": "8"
            },
            {
              "textField": "Sayaç istasyon içinde",
              "itemValue": "9"
            }
          ]
        }
      ]
    }
]
}

Updated Code: but this is wrong I want to search with TextField

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        let searchText  = textField.text! + string

        Filterdata = (AppData?.pickList?.filter({(($0.title!).localizedCaseInsensitiveContains(searchText))}))!

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

         return true
    }

Image:


回答1:


Please follow this steps for the working solution

* Step 1 -> Replace struct

    struct SectionList : Codable {
        let title : String?
        var items : [RowItems]?
        mutating func filterData(string: String) {
            self.items = self.items?.filter({ (item) -> Bool in
                if item.textField?.contains(string) == true {
                    return true
                }
                return false
            })
        }
    }

    struct Item : Codable {
        let actionType : Int?
        var pickList: [SectionList]?
        let version: Int?
        mutating func filterData(string: String) {
            guard var tempList = pickList else { return }
            for index in 0..<tempList.count {
                tempList[index].filterData(string: string)
            }
            pickList = tempList
        }
    }

* Step 2 -> Create one more variable to hold original data

    var globalAppData: Item?

* Step 3 -> Assign value to globalAppData while you parsing json

    let res = response.items?.filter { $0.actionType == 101}
    AppData = res?.first
    globalAppData = AppData

* Step 4 -> Add observer for text change

    searchTxt.addTarget(self, action: #selector(textSearchChange(_:)), for: .editingChanged)

* Step 5 -> Replace textDidChange method

    @IBAction func textSearchChange(_ sender: UITextField){

        var tempData = globalAppData
        if let text = sender.text, text.isEmpty == false {
        tempData?.filterData(string: text)
        }
        AppData = tempData

        self.tableView.reloadData()
    }

* Optional Step 6 ->

If you want case insensitive search then replace this line

    item.textField?.contains(string)

with

    item.textField?.lowercased().contains(string.lowercased())



回答2:


try to have isSearcing bool variable and filter array

public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool{
   //input text
   let searchText  = textField.text! + string
  //add matching text to arrya
   searchResult = appData.pickerlist.filter({(($0.title as! String).localizedCaseInsensitiveContains(searchText))})

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

  return true
}

if searching is enables return searchResult otherwise you main array in table delegate methods ... this is just woraround and idea.. how you can achieve that .... you can search or add predicate according to your data modal




回答3:


//You need to apply action Sent Event is editing changed

@IBAction func actionTextChange(_ sender: UITextField) {
    print("get text -----\(sender.text)")

}



回答4:


In the method textSearchChange you have the query string sender.text. You should filter the result and store it to another array. Then you can use the filteredResultArray in the tableView delegate. And every time you modify the filteredResultArray you should reload your tableView.



来源:https://stackoverflow.com/questions/60191056/how-to-implement-textfield-search-bar-to-filter-tableview-values-swift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!