Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make UITextField behave like a UISearchBar in Swift?

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".

like image 721
Marco Almeida Avatar asked Oct 19 '14 01:10

Marco Almeida


4 Answers

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
}
like image 127
Jayesh Miruliya Avatar answered Nov 09 '22 20:11

Jayesh Miruliya


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.

like image 21
Marco Almeida Avatar answered Nov 09 '22 18:11

Marco Almeida


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.

like image 3
Daniel T. Avatar answered Nov 09 '22 19:11

Daniel T.


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
}
like image 3
Krunal Patel Avatar answered Nov 09 '22 18:11

Krunal Patel