I am working on an new App using UITableView and a UISearchBar in Swift and it's already working fine. But since the final project must have a complete customized searchbar, I had to move to UITextField as the input Outlet because of the customization possibilities.
The problem is that I just can't figure out how to code so that the UITextField behaves like a UISearchBar. Have no idea of how I could filter the UITextField inputs and make the string usable with the UISearchBarDelegate methods.
So anyone could help me out with this?
EDIT: I followed Daniel's help and came up with this code, but it is returning "nil", not working.
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate {
@IBOutlet weak var txtSearchBar: UITextField!
var searchTxt = ""
let prods = ["água", "terra", "ar", "fogo"]
var searchResults:[String] = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
txtSearchBar.delegate = self
}
func textFieldDidEndEditing(textField: UITextField) {
searchTxt = textField.text
println(searchTxt)
searchResults = prods.filter({(produtos:String) -> Bool in
let nameMatch = produtos.rangeOfString(self.searchTxt, options: NSStringCompareOptions.CaseInsensitiveSearch)
println(nameMatch)
return nameMatch != nil})
}
My input was the letters "ar" but it returned "nil", when it shouldn't since one of the array's object is "ar".
Create uitextfield object:
@IBOutlet var SearchTxt: UITextField!
var search:String=""
@IBOutlet var ListTable: UITableView!
var AllData:Array<Dictionary<String,String>> = []
var SearchData:Array<Dictionary<String,String>> = []
Viewdidload:
override func viewDidLoad()
{
super.viewDidLoad()
AllData = [["pic":"list0.jpg", "name":"Angel Mark", "msg":"Hi there, I would like read your...", "time":"just now", "unread":"12"],
["pic":"list1.jpg", "name":"John Doe", "msg":"I would prefer reading on night...", "time":"56 second ago", "unread":"2"],
["pic":"list2.jpg", "name":"Krishta Hide", "msg":"Okey Great..!", "time":"2m ago", "unread":"0"],
["pic":"list3.jpg", "name":"Keithy Pamela", "msg":"I am waiting there", "time":"5h ago", "unread":"0"]
]
SearchData=AllData
}
Search in textfield delegate method:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
{
if string.isEmpty
{
search = String(search.characters.dropLast())
}
else
{
search=textField.text!+string
}
print(search)
let predicate=NSPredicate(format: "SELF.name CONTAINS[cd] %@", search)
let arr=(AllData as NSArray).filtered(using: predicate)
if arr.count > 0
{
SearchData.removeAll(keepingCapacity: true)
SearchData=arr as! Array<Dictionary<String,String>>
}
else
{
SearchData=AllData
}
ListTable.reloadData()
return true
}
Search data display in tableview :
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return SearchData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "ListCell") as! ListCell
var Data:Dictionary<String,String> = SearchData[indexPath.row]
cell.Pic.image=UIImage(named: Data["pic"]!)
cell.Name.text = Data["name"]
cell.Msg.text = Data["msg"]
cell.Time.text = Data["time"]
cell.selectionStyle = .none
return cell
}
With the help of @Daniel T. I managed to solve the problem with the following code:
func textFieldShouldReturn(textField: UITextField) -> Bool {
isFiltered = true
searchResults = prods.filter({(coisas:String) -> Bool in
let stringMatch = coisas.rangeOfString(textField.text)
return stringMatch != nil
})
println(searchResults.description)
textField.resignFirstResponder()
table.reloadData()
return true
}
Thanks @Daniel T.
Your primary question seems to be asking how to implement a class that works just like the UISearchBar. That would be a huge undertaking!
However, in your notes you just ask how to react to the search button getting tapped.
Add an IBAction and a second array to your view controller. Call the second array something like "foundItems". Connect the IBAction to the search button. When the action is called, read the text out of the text field and filter the items based on that text. Put the items that conform to the filter in the foundItems array, then call reloadData() on your table view.
In your table view data source methods, check to see if foundItems is not nil. If it isn't, then display them instead of your main items array.
You will also need some sort of cancel button. In that button's action, nil out the foundItems array and call reloadData() on your table view.
Xcode 9.2 / Swift 4 -- Working Code
@IBOutlet var tfSearchWorker: UITextField!
@IBOutlet var tblView: UITableView!
var AllData :Array<Dictionary<String,String>> = []
var SearchedData:Array<Dictionary<String,String>> = []
@ViewDidLoad
AllData = [["pic":"list0.jpg", "name":"Angel Mark", "msg":"Hi there, I would like read your...", "time":"just now", "unread":"12"],
["pic":"list1.jpg", "name":"John Doe", "msg":"I would prefer reading on night...", "time":"56 second ago", "unread":"2"],
["pic":"list2.jpg", "name":"Krishta Hide", "msg":"Okey Great..!", "time":"2m ago", "unread":"0"],
["pic":"list3.jpg", "name":"Keithy Pamela", "msg":"I am waiting there", "time":"5h ago", "unread":"0"]
]
self.SearchedData = self.AllData
self.tfSearchWorker.addTarget(self, action: #selector(searchWorkersAsPerText(_ :)), for: .editingChanged)
@Function
@objc func searchWorkersAsPerText(_ textfield:UITextField) {
self.SearchedData.removeAll()
if textfield.text?.count != 0 {
for dicData in self.AllData {
let isMachingWorker : NSString = (dicData.name!) as NSString
let range = isMachingWorker.lowercased.range(of: textfield.text!, options: NSString.CompareOptions.caseInsensitive, range: nil, locale: nil)
if range != nil {
SearchedData.append(dicData)
}
}
} else {
self.SearchedData = self.AllData
}
self.tblView.reloadData()
}
@UITableView
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.SearchedData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "ListCell") as! ListCell
var Data:Dictionary<String,String> = SearchedData[indexPath.row]
cell.Pic.image=UIImage(named: Data["pic"]!)
cell.Name.text = Data["name"]
cell.Msg.text = Data["msg"]
cell.Time.text = Data["time"]
cell.selectionStyle = .none
return cell
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With