问题
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