So I have a textField, which when the user presses, it shows a UIPickerView, which is populated from an array.
Is it possible for there to be search bar at the top of the pickerView, so the user can search for something in the pickerView?
I've not seen this done before so have no idea if it's possible?
Thanks in advance.
UIPickerView is really meant for a few options - if you need to present something that has a lot more options, I would suggest a table view with a search bar. Search Bar Tutorial is a good start.
Here is an easy solution which I have used on my recent project. First of all you need to concentrate on the following points.
Try to use UITextfield for better customization
Use table view to populate data easily inside your main viewController class.
Avoid using segue thing which is little bit annoying and old fashioned.
Try to make your code more realistic and hassle-free.
First things first :-
I am using Xcode 7.2.2 with Swift 2.1
Using native filter method to filter form the array and reuse that.
Using Array of Array type Dictionary(Swift)
Concentrating on the above points.. :)
Here is my class file. Go through the code and you will understand...
import UIKit
class ComposeMessageClass: UIViewController, UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource {
var filtered = [[String : String]]()
let customerNameForSearch: [[String : String]] = [["name": "Tuhin"], ["name": "Superman"], ["name" : "Rahul"], ["name": "Batman"], ["name": "Spiderman"]]
let customerNameToSearchTemp = ["Tuhin", "Superman", "Rahul", "Batman", "Spiderman"]
var searchActive: Bool = false
#IBOutlet weak var autofillTable: UITableView!
#IBOutlet weak var autofillTableView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
self.autofillTableView.hidden = true
self.autofillTable.delegate = self
self.autofillTable.dataSource = self
self.autofillTable.backgroundColor = tableViewBackGroundColor
self.autofillTable.separatorColor = tableViewSeperatorColor
self.autofillTable.layer.borderColor = tableViewBorderColor
}
}
override func viewWillAppear(animated: Bool) {
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidAppear(animated: Bool) {
}
func textFieldDidBeginEditing(textField: UITextField) {
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
var updatedTextString : NSString = textField.text! as NSString
updatedTextString = updatedTextString.stringByReplacingCharactersInRange(range, withString: string)
self.filtered.removeAll()
self.customerNameToSearchTemp.filter({ (text) -> Bool in
let tmp: NSString = text
let range = tmp.rangeOfString(updatedTextString as String, options: NSStringCompareOptions.CaseInsensitiveSearch)
if range.location != NSNotFound{
let dataArr = ["name": tmp as String]
filtered.append(dataArr)
}
return false
}
})
if(filtered.count == 0){
filtered = [["name" : "No results found"]]
searchActive = true
} else {
searchActive = true;
}
self.autofillTable.reloadData()
return true
}
func textFieldDidEndEditing(textField: UITextField) {
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
internal func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if(searchActive) {
return self.filtered.count
}
return self.customerNameForSearch.count
}
internal func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:UITableViewCell = self.autofillTable.dequeueReusableCellWithIdentifier("cell")! as UITableViewCell
cell.backgroundColor = UIColor.clearColor()
cell.textLabel!.textColor = tableViewCellTextColorGreen
cell.textLabel!.textAlignment = .Center
cell.selectionStyle = .None
cell.textLabel!.font = UIFont(name: "System", size:17)
if(searchActive){
if filtered[indexPath.row]["name"]! == "No results found"{
cell.textLabel!.text = self.filtered[indexPath.row]["name"]!
cell.userInteractionEnabled = false
}else{
cell.userInteractionEnabled = true
cell.textLabel?.text = self.filtered[indexPath.row]["name"]!
}
} else {
cell.userInteractionEnabled = true
cell.textLabel?.text = self.appDelegateObjForThisClass.customerNameForSearch[indexPath.row]["name"]!
}
return cell
}
internal func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
if(self.autofillTable.respondsToSelector(Selector("setSeparatorInset:"))){
self.autofillTable.separatorInset = UIEdgeInsetsZero
}
if(self.autofillTable.respondsToSelector(Selector("setLayoutMargins:"))){
self.autofillTable.layoutMargins = UIEdgeInsetsZero
}
if(cell.respondsToSelector(Selector("setLayoutMargins:"))){
cell.layoutMargins = UIEdgeInsetsZero
}
}
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath)
cell?.backgroundColor = UIColor.clearColor()
cell?.textLabel?.textColor = tableViewCellTextColorGreen
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath)
cell?.backgroundColor = UIColor.blackColor()
cell?.textLabel?.textColor = tableViewCellTextColorWhite
self.selectedCustomerId.removeAll()
if(searchActive){
self.contactNameTxtFld.text = self.filtered[indexPath.row]["name]!
}else{
self.contactNameTxtFld.text = self.appDelegateObjForThisClass.customerNameForSearch[indexPath.row]["name"]!
}
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?){
self.view.endEditing(true)
}
}
Example to set over the storyboard.
Thanks.
Hope this helped.
Any Modification or suggestion our questions would be appreciated.
I added a custom header view for the table with a textField insted of searcontroller(searchbar) and cancel button programmatically with little custmization to the tableView.
I added the following code to filter and get the updated search results
class ViewController: UIViewController,UITextFieldDelegate,UITableViewDelegate,UITableViewDataSource{
let speciality=["Andhra","Bhihar","uttharPradesh","kerala","karnataka","kashmir","thamilnadu","assam","jarkhand","dolapure","manjil","udaypoor","sholapoor","Atthapure","Barampure","Khasi"]
var filteredArray = [String]()
var shouldShowSearchResults = false
var tableView:UITableView!
var yaxis:CGFloat=10
var txtdateOfOperation:UITextField!
var searchTextField:UITextField!
var cancelButton:UIButton!
override func viewDidLoad() {
let dateOfOperationLabel=UILabel(frame:CGRectMake(8,100,200,16))
dateOfOperationLabel.text="State"
dateOfOperationLabel.textColor=UIColor.blackColor()
dateOfOperationLabel.textAlignment=NSTextAlignment.Left
dateOfOperationLabel.font = UIFont.systemFontOfSize(13.0)
dateOfOperationLabel.numberOfLines = 0;
self.view.addSubview(dateOfOperationLabel)
txtdateOfOperation=UITextField(frame: CGRectMake(8,130,300,28))
txtdateOfOperation.borderStyle=UITextBorderStyle.RoundedRect
txtdateOfOperation.returnKeyType=UIReturnKeyType.Done
txtdateOfOperation.userInteractionEnabled=true
txtdateOfOperation.keyboardType=UIKeyboardType.NumberPad
self.view.addSubview(txtdateOfOperation)
tableView=UITableView(frame: UIScreen.mainScreen().bounds, style: UITableViewStyle.Plain)
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.delegate=self
tableView.dataSource=self
tableView.reloadData()
let view=UIView(frame:CGRectMake(0,0,UIScreen.mainScreen().bounds.width,35))
view.backgroundColor=UIColor.lightGrayColor()
searchTextField=UITextField(frame:CGRectMake(8,3,view.bounds.width-70,28))
searchTextField.borderStyle=UITextBorderStyle.RoundedRect
searchTextField.returnKeyType=UIReturnKeyType.Done
searchTextField.userInteractionEnabled=true
searchTextField.delegate=self
searchTextField.placeholder="Search Here..."
searchTextField.clearButtonMode = .WhileEditing
searchTextField.leftViewMode = UITextFieldViewMode.Always
searchTextField.leftView = UIImageView(image: UIImage(named: "search-icon"))
searchTextField.addTarget(self, action: #selector(searchTextFieldDidBeginEdit), forControlEvents: UIControlEvents.EditingChanged)
view.addSubview(searchTextField)
cancelButton=UIButton(frame:CGRectMake(view.bounds.width-65,3,70,28))
cancelButton.setTitle("Cancel", forState: UIControlState.Normal)
cancelButton.setTitleColor(UIColor.grayColor(), forState: UIControlState.Normal)
cancelButton.addTarget(self, action: #selector(searchBarCancelButton_Click), forControlEvents: UIControlEvents.TouchUpInside)
cancelButton.userInteractionEnabled=false
view.addSubview(cancelButton)
tableView.tableHeaderView = view
txtdateOfOperation.inputView=tableView
searchTextField.inputView=tableView
self.tableView.reloadData()
}
func textFieldDidBeginEditing(textField: UITextField) {
shouldShowSearchResults = true
cancelButton.userInteractionEnabled=true
cancelButton.setTitleColor(UIColor(red: 51/255, green: 153/255, blue: 255/255, alpha: 1.0), forState: UIControlState.Normal)
tableView.reloadData()
}
func textFieldDidEndEditing(textField: UITextField) {
cancelButton.setTitleColor(UIColor.grayColor(), forState: UIControlState.Normal)
}
func searchTextFieldDidBeginEdit(textField:UITextField) {
if let searchText=textField.text{
filteredArray = speciality.filter({ (country) -> Bool in
let countryText: NSString = country
return (countryText.rangeOfString(searchText, options: NSStringCompareOptions.CaseInsensitiveSearch).location) != NSNotFound
})
tableView.reloadData()
}
}
func searchBarCancelButton_Click(){
searchTextField.text=nil
searchTextField.resignFirstResponder()
shouldShowSearchResults = false
tableView.reloadData()
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if shouldShowSearchResults {
return filteredArray.count
}
else {
return speciality.count
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
if shouldShowSearchResults {
cell.textLabel?.text = filteredArray[indexPath.row]
}
else {
cell.textLabel?.text = speciality[indexPath.row]
}
return cell
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 60.0
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if shouldShowSearchResults{
txtdateOfOperation.text=filteredArray[indexPath.row]
searchTextField.text=nil
searchTextField.resignFirstResponder()
txtdateOfOperation.resignFirstResponder()
shouldShowSearchResults=false
filteredArray=[String]()
tableView.reloadData()
}
else{
txtdateOfOperation.text=speciality[indexPath.row]
searchTextField.resignFirstResponder()
tableView.resignFirstResponder()
txtdateOfOperation.resignFirstResponder()
}
}
}
i tested it and its working perfectly
Related
I am using google Place Autocomplete API, i have the UITextField instead of UISearchBar with the same functionality; I am having the search estimates to be populated in a tableView. However, the results dont show the exact address; instead it only shows name of places. How can I make it so the results in the tableview are the exact address instead of places name?
Here is my code:
class DeliveryAddressVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var streetTextField: UITextField!
#IBAction func searchTextClicked(_ sender: Any) {}
#IBOutlet weak var tableView: UITableView!
var tableData=[String]()
var fetcher: GMSAutocompleteFetcher?
override func viewDidLoad() {
super.viewDidLoad()
if streetTextField.text == "" {
tableView.isHidden = true
}
self.edgesForExtendedLayout = []
// Set bounds to inner-west Sydney Australia.
let neBoundsCorner = CLLocationCoordinate2D(latitude: -33.843366,
longitude: 151.134002)
let swBoundsCorner = CLLocationCoordinate2D(latitude: -33.875725,
longitude: 151.200349)
let bounds = GMSCoordinateBounds(coordinate: neBoundsCorner,
coordinate: swBoundsCorner)
// Set up the autocomplete filter.
let filter = GMSAutocompleteFilter()
filter.type = .establishment
// Create the fetcher.
fetcher = GMSAutocompleteFetcher(bounds: bounds, filter: filter)
fetcher?.delegate = self as GMSAutocompleteFetcherDelegate
streetTextField.addTarget(self, action: #selector(DeliveryAddressVC.textFieldDidChanged(_:)), for: UIControl.Event.editingChanged)
tableView.delegate = self
tableView.dataSource = self
tableView.reloadData()
}
// MARK: -UITextField Action
#objc func textFieldDidChanged(_ textField:UITextField ){
if streetTextField.text == "" {
tableView.isHidden = true
}else {
tableView.isHidden = false
}
fetcher?.sourceTextHasChanged(streetTextField.text!)
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var section = indexPath.section
var row = indexPath.row
let cell: UITableViewCell = UITableViewCell(style: UITableViewCell.CellStyle.default, reuseIdentifier:"addCategoryCell")
cell.selectionStyle = UITableViewCell.SelectionStyle.none
cell.backgroundColor = UIColor.clear
cell.contentView.backgroundColor = UIColor.clear
cell.textLabel?.textAlignment = NSTextAlignment.left
cell.textLabel?.textColor = UIColor.black
cell.textLabel?.font = UIFont.systemFont(ofSize: 14.0)
cell.textLabel?.text = tableData[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.isHidden = true
}
}
extension DeliveryAddressVC: GMSAutocompleteFetcherDelegate {
func didAutocomplete(with predictions: [GMSAutocompletePrediction]) {
tableData.removeAll()
for prediction in predictions {
tableData.append(prediction.attributedPrimaryText.string)
//print("\n",prediction.attributedFullText.string)
//print("\n",prediction.attributedPrimaryText.string)
//print("\n********")
}
tableView.reloadData()
}
func didFailAutocompleteWithError(_ error: Error) {
print(error.localizedDescription)
}
}
Found the solution; I had to change two lines in my code:
Changed this:
filter.type = .establishment
To: filter.type = .address
AND
This: tableData.append(prediction.attributedPrimaryText.string)
To: tableData.append(prediction.attributedFullText.string)
I want to use UISwitch to show/hide a tableViewCell in a dynamic table view.
UISwitch is defined in a class of `UITableViewCell.
#IBOutlet weak var switchState: UISwitch!
And in the another file I want say if this switch is ON, the number of rows will be 5 otherwise it should be 4
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let test = PopupViewCell()
if test.switchState?.isOn == true {
detailsTableView.reloadData()
return 5
} else {
return 4
}
}
But it's not working, and it always read `return 4.
I also test it:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let test = PopupViewCell()
if test.switchState.isOn {
detailsTableView.reloadData()
return 5
} else {
return 4
}
}
But I will get this error:
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
I am not sure that I have to use some action function before this process or not, I will be appreciated if someone can help me on that.
The most beginner friendly way to do it is with a delegate. When the Switch cell detects a .valueChanged event it should forward this to the delegate. The delegate in turn updates its model of whether or not to show the switch and then reloads the tableView.
Here is a Playground example:
import UIKit
import PlaygroundSupport
protocol SwitchDelegate: class {
func toggle(isOn: Bool)
}
class SwitchCell: UITableViewCell {
private lazy var switchControl: UISwitch = {
let switchControl = UISwitch()
contentView.addSubview(switchControl)
switchControl.translatesAutoresizingMaskIntoConstraints = false
switchControl.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 12).isActive = true
switchControl.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
switchControl.addTarget(self, action: #selector(toggleSwitch(_:)), for: .valueChanged)
return switchControl
}()
private weak var delegate: SwitchDelegate?
override func awakeFromNib() {
super.awakeFromNib()
}
func configure(isOn: Bool, delegate: SwitchDelegate) {
switchControl.isOn = isOn
self.delegate = delegate
}
#objc private func toggleSwitch(_ sender: UISwitch) {
delegate?.toggle(isOn: sender.isOn)
}
}
class ViewController: UITableViewController {
private let data = (0..<5).map { $0 + 1 }
private var isOn = true
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: String(describing: UITableViewCell.self))
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count + (isOn ? 1 : 0)
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if isOn && indexPath.row == 0 {
let switchCell = SwitchCell(style: .default, reuseIdentifier: String(describing: SwitchCell.self))
switchCell.configure(isOn: isOn, delegate: self)
return switchCell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: UITableViewCell.self), for: indexPath)
let dataIndex = indexPath.row - (isOn ? 1 : 0)
cell.textLabel?.text = String(describing: data[dataIndex])
return cell
}
}
}
extension ViewController: SwitchDelegate {
func toggle(isOn: Bool) {
self.isOn = isOn
tableView.reloadData()
}
}
PlaygroundPage.current.liveView = ViewController()
I am having a weird issue where for some reason my UITableView is not being reloading after performing a search. The console prints out the correctly filtered data, but the table simply doesn't change. I have never encountered this issue, so I first attempted the solutions which naturally came to mind:
Tried tableView.reloadData() in the Main Queue
Quit Xcode, clean build, reinstall
Cleared out the derived data dir
I have found several similar issue in SO, but all of the solutions I've seen are things I've tried, mainly reloading tableview in main queue.
Hoping maybe I just simply have an issue in my code or something I'm missing.
I am running Xcode 8.3.3
import UIKit
class CategoriesViewController: UIViewController {
var isFiltering = false
var location = Location()
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var searchBar: UISearchBar!
var categoriesSearchResults = [Category]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
tableView.allowsSelection = true
tableView.keyboardDismissMode = .onDrag
let nib = UINib(nibName: "CategoryTableViewCell", bundle: nil)
self.tableView.register(nib, forCellReuseIdentifier:"CategoryTableViewCell");
searchBar.returnKeyType = UIReturnKeyType.done
searchBar.autocapitalizationType = .none
searchBar.delegate = self
}
extension CategoriesViewController : UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("HI")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if isFiltering {
return self.categoriesSearchResults.count
}
return self.location.categories.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
if let cell = self.tableView.dequeueReusableCell(withIdentifier: "CategoryTableViewCell", for: indexPath) as? CategoryTableViewCell {
var category: Category
if isFiltering {
category = self.categoriesSearchResults[indexPath.row]
} else {
category = self.location.categories[indexPath.row]
}
cell.name.text = category.name
cell.status.textColor = UIColor.lightGray
cell.status.text = "Not Verified"
}
return cell
}
}
extension CategoriesViewController : UISearchBarDelegate {
func searchBarIsEmpty() -> Bool{
return self.searchBar.text?.isEmpty ?? true
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
self.isFiltering = true
self.categoriesSearchResults.removeAll()
tableView.reloadData()
self.view.endEditing(true)
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchBarIsEmpty() {
self.view.endEditing(true)
self.isFiltering = false
} else {
self.isFiltering = true
self.categoriesSearchResults = self.location.categories.filter({ (category: Category) -> Bool in
return category.name.lowercased().contains(searchText.lowercased())
})
}
tableView.reloadData()
}
}
and my custom table view cell:
import UIKit
class CategoryTableViewCell: UITableViewCell {
#IBOutlet weak var name: UILabel!
#IBOutlet weak var status: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func prepareForReuse() {
super.prepareForReuse()
self.name.text = ""
self.status.text = ""
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Thank you in advance.
EDIT: Might also be worth mentioning, when I am actively searching, the function tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) is not called??
The scope of if let nests in its scope. In your code you are always returning let cell = UITableViewCell(). Try returning it inside the if let :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
if let cell = self.tableView.dequeueReusableCell(withIdentifier: "CategoryTableViewCell", for: indexPath) as? CategoryTableViewCell {
var category: Category
if isFiltering {
category = self.categoriesSearchResults[indexPath.row]
} else {
category = self.location.categories[indexPath.row]
}
cell.name.text = category.name
cell.status.textColor = UIColor.lightGray
cell.status.text = "Not Verified"
/// RETURN CELL HERE
return cell
}
return cell
}
I followed the suggestion here
https://stackoverflow.com/a/32948918/5447089
But it seems to work when a Text Field is inside UIViewController. In my case the TF is inside UITableViewCell and table with suggestions doesn't appear when there is some data for auto completion.
Also cellForRowAtIndexPath is not called. Other delegate methods such as numberOfRowsInSection work normally.
What can be the reason for this?
import UIKit
import CoreData
class AddElemTableViewCell: UITableViewCell, UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var myTextField: UITextField!
var autocompleteTableView = UITableView(frame: CGRectMake(0,80,320,120), style: UITableViewStyle.Plain)
var elements = [“Beer”, “Bear”, “Park”, “Pad”]
var autocompleteElements = [String]()
var currentElem: Elem!
override func awakeFromNib() {
super.awakeFromNib()
myTextField.delegate = self
autocompleteTableView.delegate = self
autocompleteTableView.dataSource = self
autocompleteTableView.scrollEnabled = true
autocompleteTableView.hidden = true
myTextField.addTarget(self, action: #selector(AddElemTableViewCell.didChangeText(_:)), forControlEvents: .EditingChanged)
}
func didChangeText(textField:UITextField) {
autocompleteTableView.hidden = false
let substring = (myTextField.text! as NSString)
searchAutocompleteEntriesWithSubstring(substring as String)
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func searchAutocompleteEntriesWithSubstring(substring: String)
{
autocompleteElements.removeAll(keepCapacity: false)
for curString in elements
{
let myString:NSString! = curString as NSString
let substringRange :NSRange! = myString.rangeOfString(substring,options: [.CaseInsensitiveSearch])
if (substringRange.location == 0)
{
autocompleteElements.append(curString)
}
}
autocompleteTableView.reloadData()
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
if textField == myTextField {
if (textField.text!.characters.count > 0) {
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedObjectContext = appDelegate.managedObjectContext
let entityElement = NSEntityDescription.entityForName("element", inManagedObjectContext: managedObjectContext)
let element = element(entity: entityElement!, insertIntoManagedObjectContext: managedObjectContext)
element.name = textField.text!
do {
try managedObjectContext.save()
} catch {
let saveError = error as NSError
print(saveError)
}
textField.text! = ""
textField.placeholder = “add new element”
self.endEditing(true)
}
}
return true
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return autocompleteElements.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let autoCompleteRowIdentifier = "AutoCompleteRowIdentifier"
let cell = UITableViewCell(style: UITableViewCellStyle.Default , reuseIdentifier: autoCompleteRowIdentifier)
let index = indexPath.row as Int
cell.textLabel!.text = autocompleteElements[index]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let selectedCell : UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
myTextField.text = selectedCell.textLabel!.text
}
}
I have been to following this guide [https://www.youtube.com/watch?v=qaLiZgUK2T0] for the creation of a swift sidebar menu: The code compiles, with out errors... I must be missing something simple somewhere....The menu does not appear. Please assist me with locating this issue.
The code for the menu is listed below in three files:
ViewController.swift:
import UIKit
class ViewController: UIViewController, SideBarDelegate {
var sideBar:SideBar = SideBar()
override func viewDidLoad() {
super.viewDidLoad()
sideBar = SideBar(sourceView: self.view, menuItems: ["first item","second item","third item"])
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func sideBarDidSelectButtonAtIndex(index: Int) {
}
}
SideBarTableViewController.swift:
import UIKit
protocol SideBarTableViewControllerDelegate{
func sideBarControlDidSelectRow(indexPath:NSIndexPath);
}
class SideBarTableViewController: UITableViewController {
var delegate:SideBarTableViewControllerDelegate?
var tableData:Array<String> = []
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData.count;
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell? = tableView.dequeueReusableCellWithIdentifier("Cell") as? UITableViewCell
if cell == nil{
cell = UITableViewCell(style :UITableViewCellStyle.Default, reuseIdentifier: "Cell")
// Configure the cell...
cell!.backgroundColor = UIColor.clearColor()
cell!.textLabel.textColor = UIColor.darkTextColor()
let selectedView:UIView = UIView(frame: CGRect (x: 0, y:0, width: cell!.frame.size.width, height: cell!.frame.size.height))
selectedView.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.3)
cell!.selectedBackgroundView = selectedView
}
cell!.textLabel.text = tableData[indexPath.row]
return cell!
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat{
return 45.0
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
delegate?.sideBarControlDidSelectRow(indexPath)
}
}
SideBar.swift
import UIKit
#objc protocol SideBarDelegate{
func sideBarDidSelectButtonAtIndex(index:Int)
optional func sideBarWillClose()
optional func sideBarWillOpen()
}
class SideBar: NSObject, SideBarTableViewControllerDelegate {
let barWidth : CGFloat = 150;
let sideBarTableViewTopInset:CGFloat = 64.0;
let sideBarContainerView: UIView = UIView()
let sideBarTableViewController: SideBarTableViewController = SideBarTableViewController()
let orginView : UIView!
var animator: UIDynamicAnimator!
var delegate:SideBarDelegate?
var isSideBarOpen:Bool = false
override init(){
super.init()
}
init(sourceView: UIView, menuItems:Array<String>){
super.init()
orginView = sourceView
sideBarTableViewController.tableData = menuItems
animator = UIDynamicAnimator(referenceView: orginView)
let showGestureRecognizer:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: "handleSwipe:")
showGestureRecognizer.direction = UISwipeGestureRecognizerDirection.Right
orginView.addGestureRecognizer(showGestureRecognizer)
let hideGesturerecognizer:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: "handleSwipe:")
hideGesturerecognizer.direction = UISwipeGestureRecognizerDirection.Left
orginView.addGestureRecognizer(hideGesturerecognizer)
}
func setupSideBar(){
sideBarContainerView.frame = CGRectMake(-barWidth - 1,orginView.frame.origin.y, barWidth, orginView.frame.size.height)
sideBarContainerView.backgroundColor = UIColor.clearColor()
sideBarContainerView.clipsToBounds = false
orginView.addSubview(sideBarContainerView)
let blurView:UIVisualEffectView = UIVisualEffectView(effect:
UIBlurEffect(style: UIBlurEffectStyle.Light))
blurView.frame = sideBarContainerView.bounds
sideBarContainerView.addSubview(blurView)
sideBarTableViewController.delegate = self
sideBarTableViewController.tableView.frame = sideBarContainerView.bounds
sideBarTableViewController.tableView.clipsToBounds = false
sideBarTableViewController.tableView.separatorStyle = UITableViewCellSeparatorStyle.None
sideBarContainerView.backgroundColor = UIColor.clearColor()
sideBarTableViewController.tableView.scrollsToTop = false
sideBarTableViewController.tableView.contentInset = UIEdgeInsetsMake(sideBarTableViewTopInset, 0,0,0)
sideBarTableViewController.tableView.reloadData()
sideBarContainerView.addSubview(sideBarTableViewController.tableView)
}
func handleSwipe(recognizer:UISwipeGestureRecognizer){
if (recognizer.direction == UISwipeGestureRecognizerDirection.Left){
showSideBar(false)
delegate?.sideBarWillClose?()
}else{
showSideBar(true)
delegate?.sideBarWillClose?()
}
}
func showSideBar(shouldOpen:Bool){
animator.removeAllBehaviors()
isSideBarOpen = shouldOpen
let gravityX:CGFloat = (shouldOpen) ? 0.5 : -0.5
let magnitude:CGFloat = (shouldOpen) ? 20 : -20
let boundryX: CGFloat = (shouldOpen) ? barWidth : -barWidth - 1
let gravityBehavior:UIGravityBehavior = UIGravityBehavior(items: [sideBarContainerView])
gravityBehavior.gravityDirection = CGVectorMake(gravityX, 0)
let collisonBehavior:UICollisionBehavior = UICollisionBehavior(items: [sideBarContainerView])
collisonBehavior.addBoundaryWithIdentifier("sideBarBoundary", fromPoint: CGPointMake(boundryX, 20), toPoint: CGPointMake(boundryX, orginView.frame.size.height))
animator.addBehavior(collisonBehavior)
let pushBehavior:UIPushBehavior = UIPushBehavior(items: [sideBarContainerView], mode: UIPushBehaviorMode.Instantaneous)
animator.addBehavior(pushBehavior)
let sideBarBehavior:UIDynamicItemBehavior = UIDynamicItemBehavior(items: [sideBarContainerView])
sideBarBehavior.elasticity = 0.3
animator.addBehavior(sideBarBehavior)
}
func sideBarControlDidSelectRow(indexPath: NSIndexPath) {
delegate?.sideBarDidSelectButtonAtIndex(indexPath.row)
}
}
I went through and debugged the project file when you download the source code and all I had to do to get it to work was make a bunch of minor changes to the SideBarTableViewController.swift and everything worked for me. Here it is:
import UIKit
protocol SideBarTableViewControllerDelegate{
func sideBarControlDidSelectRow(indexPath:NSIndexPath)
}
class SideBarTableViewController: UITableViewController {
var delegate:SideBarTableViewControllerDelegate?
var tableData:Array<String> = []
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("Cell") as? UITableViewCell
if cell == nil{
cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")
// Configure the cell...
cell?.backgroundColor = UIColor.clearColor()
cell?.textLabel?.textColor = UIColor.darkTextColor()
let selectedView:UIView = UIView(frame: CGRect(x: 0, y: 0, width: cell!.frame.size.width, height: cell!.frame.size.height))
selectedView.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.3)
cell!.selectedBackgroundView = selectedView
}
cell?.textLabel?.text = tableData[indexPath.row]
return cell!
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 45.0
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
delegate?.sideBarControlDidSelectRow(indexPath)
}
}