From 3c9d14d9414b8c6a3c2baa2894d591edbdb3e060 Mon Sep 17 00:00:00 2001 From: Prathap Dodla Date: Fri, 4 Aug 2017 14:07:04 +0530 Subject: [PATCH 1/4] Added direction support for the results table view. Now users can setup direction of the results table by using 'auto', 'down' and 'up' enums. Setting up 'auto' behave the similar way earlier. --- .../SearchTextField/MainViewController.swift | 46 ++++--- SearchTextField/Classes/SearchTextField.swift | 117 +++++++++++++----- 2 files changed, 119 insertions(+), 44 deletions(-) diff --git a/Example/SearchTextField/MainViewController.swift b/Example/SearchTextField/MainViewController.swift index 76579bb..d616b37 100644 --- a/Example/SearchTextField/MainViewController.swift +++ b/Example/SearchTextField/MainViewController.swift @@ -10,7 +10,7 @@ import UIKit import SearchTextField class MainViewController: UITableViewController { - + @IBOutlet weak var countryTextField: SearchTextField! @IBOutlet weak var acronymTextField: SearchTextField! @IBOutlet weak var countryInLineTextField: SearchTextField! @@ -19,6 +19,8 @@ class MainViewController: UITableViewController { override func viewDidLoad() { super.viewDidLoad() + tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0) + tableView.tableFooterView = UIView() // 1 - Configure a simple search text field @@ -26,19 +28,18 @@ class MainViewController: UITableViewController { // 2 - Configure a custom search text field configureCustomSearchTextField() - + // 3 - Configure an "inline" suggestions search text field configureSimpleInLineSearchTextField() - + // 4 - Configure a custom "inline" suggestions search text field configureCustomInLineSearchTextField() } // 1 - Configure a simple search text view fileprivate func configureSimpleSearchTextField() { - // Start visible - Default: false - countryTextField.startVisible = true - + // Start visible even without user's interaction as soon as created - Default: false + countryTextField.startVisibleWithoutInteraction = true // Set data source let countries = localCountries() @@ -51,13 +52,22 @@ class MainViewController: UITableViewController { // Set theme - Default: light acronymTextField.theme = SearchTextFieldTheme.lightTheme() + // Define a header - Default: nothing + let header = UILabel(frame: CGRect(x: 0, y: 0, width: acronymTextField.frame.width, height: 30)) + header.backgroundColor = UIColor.lightGray.withAlphaComponent(0.3) + header.textAlignment = .center + header.font = UIFont.systemFont(ofSize: 14) + header.text = "Pick your option" + acronymTextField.resultsListHeader = header + + // Modify current theme properties acronymTextField.theme.font = UIFont.systemFont(ofSize: 12) - acronymTextField.theme.bgColor = UIColor (red: 0.9, green: 0.9, blue: 0.9, alpha: 0.3) - acronymTextField.theme.borderColor = UIColor (red: 0.9, green: 0.9, blue: 0.9, alpha: 1) - acronymTextField.theme.separatorColor = UIColor (red: 0.9, green: 0.9, blue: 0.9, alpha: 0.5) + acronymTextField.theme.bgColor = UIColor.lightGray.withAlphaComponent(0.2) + acronymTextField.theme.borderColor = UIColor.lightGray.withAlphaComponent(0.5) + acronymTextField.theme.separatorColor = UIColor.lightGray.withAlphaComponent(0.5) acronymTextField.theme.cellHeight = 50 - acronymTextField.theme.placeholderColor = UIColor.brown.withAlphaComponent(0.5) + acronymTextField.theme.placeholderColor = UIColor.lightGray // Max number of results - Default: No limit acronymTextField.maxNumberOfResults = 5 @@ -67,10 +77,10 @@ class MainViewController: UITableViewController { // Set specific comparision options - Default: .caseInsensitive acronymTextField.comparisonOptions = [.caseInsensitive] - + // You can force the results list to support RTL languages - Default: false acronymTextField.forceRightToLeft = false - + // Customize highlight attributes - Default: Bold acronymTextField.highlightAttributes = [NSBackgroundColorAttributeName: UIColor.yellow, NSFontAttributeName:UIFont.boldSystemFont(ofSize: 12)] @@ -84,6 +94,9 @@ class MainViewController: UITableViewController { self.acronymTextField.text = item.title } + // You can force the results table appear always top + acronymTextField.direction = .up + // Update data source when the user stops typing acronymTextField.userStoppedTypingHandler = { if let criteria = self.acronymTextField.text { @@ -109,11 +122,12 @@ class MainViewController: UITableViewController { // Define the inline mode countryInLineTextField.inlineMode = true + // Set data source let countries = localCountries() countryInLineTextField.filterStrings(countries) } - + // 4 - Configure a custom inline search text view fileprivate func configureCustomInLineSearchTextField() { // Define the inline mode @@ -125,7 +139,7 @@ class MainViewController: UITableViewController { // Set data source emailInlineTextField.filterStrings(["gmail.com", "yahoo.com", "yahoo.com.ar"]) } - + // Hide keyboard when touching the screen override func touchesEnded(_ touches: Set, with event: UIEvent?) { view.endEditing(true) @@ -197,6 +211,6 @@ class MainViewController: UITableViewController { task.resume() } } - - + + } diff --git a/SearchTextField/Classes/SearchTextField.swift b/SearchTextField/Classes/SearchTextField.swift index 732ad0b..469e784 100755 --- a/SearchTextField/Classes/SearchTextField.swift +++ b/SearchTextField/Classes/SearchTextField.swift @@ -43,6 +43,15 @@ open class SearchTextField: UITextField { /// Show the suggestions list without filter when the text field is focused open var startVisible = false + /// Show the suggestions list without filter even if the text field is not focused + open var startVisibleWithoutInteraction = false { + didSet { + if startVisibleWithoutInteraction { + textFieldDidChange() + } + } + } + /// Set an array of SearchTextFieldItem's to be used for suggestions open func filterItems(_ items: [SearchTextFieldItem]) { filterDataSource = items @@ -56,7 +65,7 @@ open class SearchTextField: UITextField { items.append(SearchTextFieldItem(title: value)) } - filterDataSource = items + filterItems(items) } /// Closure to handle when the user pick an item @@ -96,30 +105,43 @@ open class SearchTextField: UITextField { /// Only valid when InlineMode is true. The suggestions appear after typing the provided string (or even better a character like '@') open var startFilteringAfter: String? + /// Min number of characters to start filtering + open var minCharactersNumberToStartFiltering: Int = 0 /// If startFilteringAfter is set, and startSuggestingInmediately is true, the list of suggestions appear inmediately open var startSuggestingInmediately = false + /// Allow to decide the comparision options open var comparisonOptions: NSString.CompareOptions = [.caseInsensitive] + /// Set the results list's header + open var resultsListHeader: UIView? + + /// Set the direction of the results table. If nothing sets default is automatic + open var direction: Direction = .auto + //////////////////////////////////////////////////////////////////////// // Private implementation fileprivate var tableView: UITableView? fileprivate var shadowView: UIView? - fileprivate var direction: Direction = .down fileprivate var fontConversionRate: CGFloat = 0.7 fileprivate var keyboardFrame: CGRect? fileprivate var timer: Timer? = nil fileprivate var placeholderLabel: UILabel? fileprivate static let cellIdentifier = "APSearchTextFieldCell" fileprivate let indicator = UIActivityIndicatorView(activityIndicatorStyle: .gray) + fileprivate var maxTableViewSize: CGFloat = 0 fileprivate var filteredResults = [SearchTextFieldItem]() fileprivate var filterDataSource = [SearchTextFieldItem]() { didSet { - filter(false) + filter(forceShowAll: false) buildSearchTableView() + + if startVisibleWithoutInteraction { + textFieldDidChange() + } } } @@ -129,6 +151,11 @@ open class SearchTextField: UITextField { NotificationCenter.default.removeObserver(self) } + open override func willMove(toWindow newWindow: UIWindow?) { + super.willMove(toWindow: newWindow) + tableView?.removeFromSuperview() + } + override open func willMove(toSuperview newSuperview: UIView?) { super.willMove(toSuperview: newSuperview) @@ -170,6 +197,7 @@ open class SearchTextField: UITextField { tableView.dataSource = self tableView.delegate = self tableView.separatorInset = UIEdgeInsets.zero + tableView.tableHeaderView = resultsListHeader if forceRightToLeft { tableView.semanticContentAttribute = .forceRightToLeft } @@ -227,19 +255,24 @@ open class SearchTextField: UITextField { } if let tableView = tableView { - let positionGap: CGFloat = 0 guard let frame = self.superview?.convert(self.frame, to: nil) else { return } - if self.direction == .down { + if self.direction == .down || self.direction == .auto { + var tableHeight: CGFloat = 0 if keyboardIsShowing, let keyboardHeight = keyboardFrame?.size.height { - tableHeight = min((tableView.contentSize.height + positionGap), (UIScreen.main.bounds.size.height - frame.origin.y - frame.height - keyboardHeight)) + tableHeight = min((tableView.contentSize.height), (UIScreen.main.bounds.size.height - frame.origin.y - frame.height - keyboardHeight)) } else { - tableHeight = min((tableView.contentSize.height + positionGap), (UIScreen.main.bounds.size.height - frame.origin.y - frame.height)) + tableHeight = min((tableView.contentSize.height), (UIScreen.main.bounds.size.height - frame.origin.y - frame.height)) } if maxResultsListHeight > 0 { - tableHeight = min(tableHeight, CGFloat(self.maxResultsListHeight)) + tableHeight = min(tableHeight, CGFloat(maxResultsListHeight)) + } + + // Set a bottom margin of 10p + if tableHeight < tableView.contentSize.height { + tableHeight -= 10 } var tableViewFrame = CGRect(x: 0, y: 0, width: frame.size.width - 4, height: tableHeight) @@ -256,9 +289,9 @@ open class SearchTextField: UITextField { shadowFrame.origin.y = tableView.frame.origin.y shadowView!.frame = shadowFrame } else { - let tableHeight = min((tableView.contentSize.height + positionGap), (UIScreen.main.bounds.size.height - frame.origin.y - theme.cellHeight * 2)) + let tableHeight = min((tableView.contentSize.height), (UIScreen.main.bounds.size.height - frame.origin.y - theme.cellHeight)) UIView.animate(withDuration: 0.2, animations: { [weak self] in - self?.tableView?.frame = CGRect(x: frame.origin.x + 2, y: (frame.origin.y - tableHeight + positionGap), width: frame.size.width - 4, height: tableHeight) + self?.tableView?.frame = CGRect(x: frame.origin.x + 2, y: (frame.origin.y - tableHeight), width: frame.size.width - 4, height: tableHeight) self?.shadowView?.frame = CGRect(x: frame.origin.x + 3, y: (frame.origin.y + 3), width: frame.size.width - 6, height: 1) }) } @@ -292,7 +325,9 @@ open class SearchTextField: UITextField { open func keyboardWillHide(_ notification: Notification) { if keyboardIsShowing { keyboardIsShowing = false - direction = .down + if direction == .auto { + direction = .down + } redrawSearchTableView() } } @@ -315,6 +350,9 @@ open class SearchTextField: UITextField { if !inlineMode && tableView == nil { buildSearchTableView() } + + interactedWith = true + // Detect pauses while typing timer?.invalidate() timer = Timer.scheduledTimer(timeInterval: 0.8, target: self, selector: #selector(SearchTextField.typingDidStop), userInfo: self, repeats: false) @@ -322,12 +360,12 @@ open class SearchTextField: UITextField { if text!.isEmpty { clearResults() tableView?.reloadData() - if startVisible { - filter(true) + if startVisible || startVisibleWithoutInteraction { + filter(forceShowAll: true) } self.placeholderLabel?.text = "" } else { - filter(false) + filter(forceShowAll: false) prepareDrawTableResult() } @@ -335,9 +373,9 @@ open class SearchTextField: UITextField { } open func textFieldDidBeginEditing() { - if startVisible && text!.isEmpty { + if (startVisible || startVisibleWithoutInteraction) && text!.isEmpty { clearResults() - filter(true) + filter(forceShowAll: true) } placeholderLabel?.attributedText = nil } @@ -365,9 +403,23 @@ open class SearchTextField: UITextField { } } - fileprivate func filter(_ addAll: Bool) { + open func hideResultsList() { + if let tableFrame:CGRect = tableView?.frame { + let newFrame = CGRect(x: tableFrame.origin.x, y: tableFrame.origin.y, width: tableFrame.size.width, height: 0.0) + UIView.animate(withDuration: 0.2, animations: { [weak self] in + self?.tableView?.frame = newFrame + }) + + } + } + + fileprivate func filter(forceShowAll addAll: Bool) { clearResults() + if text!.characters.count < minCharactersNumberToStartFiltering { + return + } + for i in 0 ..< filterDataSource.count { var item = filterDataSource[i] @@ -457,18 +509,26 @@ open class SearchTextField: UITextField { // MARK: - Prepare for draw table result fileprivate func prepareDrawTableResult() { - guard let frame = self.superview?.convert(self.frame, to: UIApplication.shared.keyWindow) else { return } - if let keyboardFrame = keyboardFrame { - var newFrame = frame - newFrame.size.height += theme.cellHeight - - if keyboardFrame.intersects(newFrame) { - direction = .up + if direction == .auto {//if direction is not auto ignore and force the layout to draw AS IS required. + guard let frame = self.superview?.convert(self.frame, to: UIApplication.shared.keyWindow) else { return } + if let keyboardFrame = keyboardFrame { + var newFrame = frame + newFrame.size.height += theme.cellHeight + + if keyboardFrame.intersects(newFrame) { + direction = .up + } else { + direction = .down + } + + redrawSearchTableView() } else { - direction = .down + if self.center.y + theme.cellHeight > UIApplication.shared.keyWindow!.frame.size.height { + direction = .up + } else { + direction = .down + } } - - redrawSearchTableView() } } } @@ -592,7 +652,8 @@ public typealias SearchTextFieldItemHandler = (_ filteredResults: [SearchTextFie //////////////////////////////////////////////////////////////////////// // Suggestions List Direction -enum Direction { +public enum Direction { case down case up + case auto//Default } From 21b52473a302f40a0ebb432c199bceeeb42e46e2 Mon Sep 17 00:00:00 2001 From: Prathap Dodla Date: Fri, 4 Aug 2017 14:14:23 +0530 Subject: [PATCH 2/4] feature/direction-change-support Added direction support for the results table view. Now users can setup direction of the results table by using 'auto', 'down' and 'up' enums. Setting up 'auto' behave the similar way earlier. --- .../SearchTextField/MainViewController.swift | 28 +++-- SearchTextField/Classes/SearchTextField.swift | 117 +++++++++++++----- 2 files changed, 110 insertions(+), 35 deletions(-) diff --git a/Example/SearchTextField/MainViewController.swift b/Example/SearchTextField/MainViewController.swift index 76579bb..725d02f 100644 --- a/Example/SearchTextField/MainViewController.swift +++ b/Example/SearchTextField/MainViewController.swift @@ -19,6 +19,8 @@ class MainViewController: UITableViewController { override func viewDidLoad() { super.viewDidLoad() + tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0) + tableView.tableFooterView = UIView() // 1 - Configure a simple search text field @@ -36,9 +38,8 @@ class MainViewController: UITableViewController { // 1 - Configure a simple search text view fileprivate func configureSimpleSearchTextField() { - // Start visible - Default: false - countryTextField.startVisible = true - + // Start visible even without user's interaction as soon as created - Default: false + countryTextField.startVisibleWithoutInteraction = true // Set data source let countries = localCountries() @@ -51,13 +52,22 @@ class MainViewController: UITableViewController { // Set theme - Default: light acronymTextField.theme = SearchTextFieldTheme.lightTheme() + // Define a header - Default: nothing + let header = UILabel(frame: CGRect(x: 0, y: 0, width: acronymTextField.frame.width, height: 30)) + header.backgroundColor = UIColor.lightGray.withAlphaComponent(0.3) + header.textAlignment = .center + header.font = UIFont.systemFont(ofSize: 14) + header.text = "Pick your option" + acronymTextField.resultsListHeader = header + + // Modify current theme properties acronymTextField.theme.font = UIFont.systemFont(ofSize: 12) - acronymTextField.theme.bgColor = UIColor (red: 0.9, green: 0.9, blue: 0.9, alpha: 0.3) - acronymTextField.theme.borderColor = UIColor (red: 0.9, green: 0.9, blue: 0.9, alpha: 1) - acronymTextField.theme.separatorColor = UIColor (red: 0.9, green: 0.9, blue: 0.9, alpha: 0.5) + acronymTextField.theme.bgColor = UIColor.lightGray.withAlphaComponent(0.2) + acronymTextField.theme.borderColor = UIColor.lightGray.withAlphaComponent(0.5) + acronymTextField.theme.separatorColor = UIColor.lightGray.withAlphaComponent(0.5) acronymTextField.theme.cellHeight = 50 - acronymTextField.theme.placeholderColor = UIColor.brown.withAlphaComponent(0.5) + acronymTextField.theme.placeholderColor = UIColor.lightGray // Max number of results - Default: No limit acronymTextField.maxNumberOfResults = 5 @@ -84,6 +94,9 @@ class MainViewController: UITableViewController { self.acronymTextField.text = item.title } + // You can force the results table appear always top + acronymTextField.direction = .up + // Update data source when the user stops typing acronymTextField.userStoppedTypingHandler = { if let criteria = self.acronymTextField.text { @@ -109,6 +122,7 @@ class MainViewController: UITableViewController { // Define the inline mode countryInLineTextField.inlineMode = true + // Set data source let countries = localCountries() countryInLineTextField.filterStrings(countries) diff --git a/SearchTextField/Classes/SearchTextField.swift b/SearchTextField/Classes/SearchTextField.swift index 732ad0b..469e784 100755 --- a/SearchTextField/Classes/SearchTextField.swift +++ b/SearchTextField/Classes/SearchTextField.swift @@ -43,6 +43,15 @@ open class SearchTextField: UITextField { /// Show the suggestions list without filter when the text field is focused open var startVisible = false + /// Show the suggestions list without filter even if the text field is not focused + open var startVisibleWithoutInteraction = false { + didSet { + if startVisibleWithoutInteraction { + textFieldDidChange() + } + } + } + /// Set an array of SearchTextFieldItem's to be used for suggestions open func filterItems(_ items: [SearchTextFieldItem]) { filterDataSource = items @@ -56,7 +65,7 @@ open class SearchTextField: UITextField { items.append(SearchTextFieldItem(title: value)) } - filterDataSource = items + filterItems(items) } /// Closure to handle when the user pick an item @@ -96,30 +105,43 @@ open class SearchTextField: UITextField { /// Only valid when InlineMode is true. The suggestions appear after typing the provided string (or even better a character like '@') open var startFilteringAfter: String? + /// Min number of characters to start filtering + open var minCharactersNumberToStartFiltering: Int = 0 /// If startFilteringAfter is set, and startSuggestingInmediately is true, the list of suggestions appear inmediately open var startSuggestingInmediately = false + /// Allow to decide the comparision options open var comparisonOptions: NSString.CompareOptions = [.caseInsensitive] + /// Set the results list's header + open var resultsListHeader: UIView? + + /// Set the direction of the results table. If nothing sets default is automatic + open var direction: Direction = .auto + //////////////////////////////////////////////////////////////////////// // Private implementation fileprivate var tableView: UITableView? fileprivate var shadowView: UIView? - fileprivate var direction: Direction = .down fileprivate var fontConversionRate: CGFloat = 0.7 fileprivate var keyboardFrame: CGRect? fileprivate var timer: Timer? = nil fileprivate var placeholderLabel: UILabel? fileprivate static let cellIdentifier = "APSearchTextFieldCell" fileprivate let indicator = UIActivityIndicatorView(activityIndicatorStyle: .gray) + fileprivate var maxTableViewSize: CGFloat = 0 fileprivate var filteredResults = [SearchTextFieldItem]() fileprivate var filterDataSource = [SearchTextFieldItem]() { didSet { - filter(false) + filter(forceShowAll: false) buildSearchTableView() + + if startVisibleWithoutInteraction { + textFieldDidChange() + } } } @@ -129,6 +151,11 @@ open class SearchTextField: UITextField { NotificationCenter.default.removeObserver(self) } + open override func willMove(toWindow newWindow: UIWindow?) { + super.willMove(toWindow: newWindow) + tableView?.removeFromSuperview() + } + override open func willMove(toSuperview newSuperview: UIView?) { super.willMove(toSuperview: newSuperview) @@ -170,6 +197,7 @@ open class SearchTextField: UITextField { tableView.dataSource = self tableView.delegate = self tableView.separatorInset = UIEdgeInsets.zero + tableView.tableHeaderView = resultsListHeader if forceRightToLeft { tableView.semanticContentAttribute = .forceRightToLeft } @@ -227,19 +255,24 @@ open class SearchTextField: UITextField { } if let tableView = tableView { - let positionGap: CGFloat = 0 guard let frame = self.superview?.convert(self.frame, to: nil) else { return } - if self.direction == .down { + if self.direction == .down || self.direction == .auto { + var tableHeight: CGFloat = 0 if keyboardIsShowing, let keyboardHeight = keyboardFrame?.size.height { - tableHeight = min((tableView.contentSize.height + positionGap), (UIScreen.main.bounds.size.height - frame.origin.y - frame.height - keyboardHeight)) + tableHeight = min((tableView.contentSize.height), (UIScreen.main.bounds.size.height - frame.origin.y - frame.height - keyboardHeight)) } else { - tableHeight = min((tableView.contentSize.height + positionGap), (UIScreen.main.bounds.size.height - frame.origin.y - frame.height)) + tableHeight = min((tableView.contentSize.height), (UIScreen.main.bounds.size.height - frame.origin.y - frame.height)) } if maxResultsListHeight > 0 { - tableHeight = min(tableHeight, CGFloat(self.maxResultsListHeight)) + tableHeight = min(tableHeight, CGFloat(maxResultsListHeight)) + } + + // Set a bottom margin of 10p + if tableHeight < tableView.contentSize.height { + tableHeight -= 10 } var tableViewFrame = CGRect(x: 0, y: 0, width: frame.size.width - 4, height: tableHeight) @@ -256,9 +289,9 @@ open class SearchTextField: UITextField { shadowFrame.origin.y = tableView.frame.origin.y shadowView!.frame = shadowFrame } else { - let tableHeight = min((tableView.contentSize.height + positionGap), (UIScreen.main.bounds.size.height - frame.origin.y - theme.cellHeight * 2)) + let tableHeight = min((tableView.contentSize.height), (UIScreen.main.bounds.size.height - frame.origin.y - theme.cellHeight)) UIView.animate(withDuration: 0.2, animations: { [weak self] in - self?.tableView?.frame = CGRect(x: frame.origin.x + 2, y: (frame.origin.y - tableHeight + positionGap), width: frame.size.width - 4, height: tableHeight) + self?.tableView?.frame = CGRect(x: frame.origin.x + 2, y: (frame.origin.y - tableHeight), width: frame.size.width - 4, height: tableHeight) self?.shadowView?.frame = CGRect(x: frame.origin.x + 3, y: (frame.origin.y + 3), width: frame.size.width - 6, height: 1) }) } @@ -292,7 +325,9 @@ open class SearchTextField: UITextField { open func keyboardWillHide(_ notification: Notification) { if keyboardIsShowing { keyboardIsShowing = false - direction = .down + if direction == .auto { + direction = .down + } redrawSearchTableView() } } @@ -315,6 +350,9 @@ open class SearchTextField: UITextField { if !inlineMode && tableView == nil { buildSearchTableView() } + + interactedWith = true + // Detect pauses while typing timer?.invalidate() timer = Timer.scheduledTimer(timeInterval: 0.8, target: self, selector: #selector(SearchTextField.typingDidStop), userInfo: self, repeats: false) @@ -322,12 +360,12 @@ open class SearchTextField: UITextField { if text!.isEmpty { clearResults() tableView?.reloadData() - if startVisible { - filter(true) + if startVisible || startVisibleWithoutInteraction { + filter(forceShowAll: true) } self.placeholderLabel?.text = "" } else { - filter(false) + filter(forceShowAll: false) prepareDrawTableResult() } @@ -335,9 +373,9 @@ open class SearchTextField: UITextField { } open func textFieldDidBeginEditing() { - if startVisible && text!.isEmpty { + if (startVisible || startVisibleWithoutInteraction) && text!.isEmpty { clearResults() - filter(true) + filter(forceShowAll: true) } placeholderLabel?.attributedText = nil } @@ -365,9 +403,23 @@ open class SearchTextField: UITextField { } } - fileprivate func filter(_ addAll: Bool) { + open func hideResultsList() { + if let tableFrame:CGRect = tableView?.frame { + let newFrame = CGRect(x: tableFrame.origin.x, y: tableFrame.origin.y, width: tableFrame.size.width, height: 0.0) + UIView.animate(withDuration: 0.2, animations: { [weak self] in + self?.tableView?.frame = newFrame + }) + + } + } + + fileprivate func filter(forceShowAll addAll: Bool) { clearResults() + if text!.characters.count < minCharactersNumberToStartFiltering { + return + } + for i in 0 ..< filterDataSource.count { var item = filterDataSource[i] @@ -457,18 +509,26 @@ open class SearchTextField: UITextField { // MARK: - Prepare for draw table result fileprivate func prepareDrawTableResult() { - guard let frame = self.superview?.convert(self.frame, to: UIApplication.shared.keyWindow) else { return } - if let keyboardFrame = keyboardFrame { - var newFrame = frame - newFrame.size.height += theme.cellHeight - - if keyboardFrame.intersects(newFrame) { - direction = .up + if direction == .auto {//if direction is not auto ignore and force the layout to draw AS IS required. + guard let frame = self.superview?.convert(self.frame, to: UIApplication.shared.keyWindow) else { return } + if let keyboardFrame = keyboardFrame { + var newFrame = frame + newFrame.size.height += theme.cellHeight + + if keyboardFrame.intersects(newFrame) { + direction = .up + } else { + direction = .down + } + + redrawSearchTableView() } else { - direction = .down + if self.center.y + theme.cellHeight > UIApplication.shared.keyWindow!.frame.size.height { + direction = .up + } else { + direction = .down + } } - - redrawSearchTableView() } } } @@ -592,7 +652,8 @@ public typealias SearchTextFieldItemHandler = (_ filteredResults: [SearchTextFie //////////////////////////////////////////////////////////////////////// // Suggestions List Direction -enum Direction { +public enum Direction { case down case up + case auto//Default } From 3f63cab388e0b8c1badd5a6edcd01b5a6c5df398 Mon Sep 17 00:00:00 2001 From: Prathap Dodla Date: Wed, 9 Aug 2017 22:12:57 +0530 Subject: [PATCH 3/4] feature/padding-support: Added padding to the theme. This enables the gap between the results table view and search field as desired. --- Example/SearchTextField/MainViewController.swift | 2 ++ SearchTextField/Classes/SearchTextField.swift | 12 +++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Example/SearchTextField/MainViewController.swift b/Example/SearchTextField/MainViewController.swift index 47c8fef..e3752b1 100644 --- a/Example/SearchTextField/MainViewController.swift +++ b/Example/SearchTextField/MainViewController.swift @@ -67,6 +67,8 @@ class MainViewController: UITableViewController { acronymTextField.theme.separatorColor = UIColor.lightGray.withAlphaComponent(0.5) acronymTextField.theme.cellHeight = 50 acronymTextField.theme.placeholderColor = UIColor.lightGray + //Adds padding to the table view. This leaves a visible gap between the text field and search field. + acronymTextField.theme.padding = 10 // Max number of results - Default: No limit acronymTextField.maxNumberOfResults = 5 diff --git a/SearchTextField/Classes/SearchTextField.swift b/SearchTextField/Classes/SearchTextField.swift index 469e784..11154d4 100755 --- a/SearchTextField/Classes/SearchTextField.swift +++ b/SearchTextField/Classes/SearchTextField.swift @@ -278,7 +278,7 @@ open class SearchTextField: UITextField { var tableViewFrame = CGRect(x: 0, y: 0, width: frame.size.width - 4, height: tableHeight) tableViewFrame.origin = self.convert(tableViewFrame.origin, to: nil) tableViewFrame.origin.x += 2 - tableViewFrame.origin.y += frame.size.height + 2 + tableViewFrame.origin.y += frame.size.height + 2 + theme.padding! UIView.animate(withDuration: 0.2, animations: { [weak self] in self?.tableView?.frame = tableViewFrame }) @@ -291,7 +291,7 @@ open class SearchTextField: UITextField { } else { let tableHeight = min((tableView.contentSize.height), (UIScreen.main.bounds.size.height - frame.origin.y - theme.cellHeight)) UIView.animate(withDuration: 0.2, animations: { [weak self] in - self?.tableView?.frame = CGRect(x: frame.origin.x + 2, y: (frame.origin.y - tableHeight), width: frame.size.width - 4, height: tableHeight) + self?.tableView?.frame = CGRect(x: frame.origin.x + 2, y: (frame.origin.y - tableHeight), width: frame.size.width - 4, height: tableHeight - (self?.theme.padding!)!) self?.shadowView?.frame = CGRect(x: frame.origin.x + 3, y: (frame.origin.y + 3), width: frame.size.width - 6, height: 1) }) } @@ -599,22 +599,24 @@ public struct SearchTextFieldTheme { public var font: UIFont public var fontColor: UIColor public var placeholderColor: UIColor? + public var padding: CGFloat? - init(cellHeight: CGFloat, bgColor:UIColor, borderColor: UIColor, separatorColor: UIColor, font: UIFont, fontColor: UIColor) { + init(cellHeight: CGFloat, bgColor:UIColor, borderColor: UIColor, separatorColor: UIColor, font: UIFont, fontColor: UIColor, padding: CGFloat) { self.cellHeight = cellHeight self.borderColor = borderColor self.separatorColor = separatorColor self.bgColor = bgColor self.font = font self.fontColor = fontColor + self.padding = padding } public static func lightTheme() -> SearchTextFieldTheme { - return SearchTextFieldTheme(cellHeight: 30, bgColor: UIColor (red: 1, green: 1, blue: 1, alpha: 0.6), borderColor: UIColor (red: 0.9, green: 0.9, blue: 0.9, alpha: 1.0), separatorColor: UIColor.clear, font: UIFont.systemFont(ofSize: 10), fontColor: UIColor.black) + return SearchTextFieldTheme(cellHeight: 30, bgColor: UIColor (red: 1, green: 1, blue: 1, alpha: 0.6), borderColor: UIColor (red: 0.9, green: 0.9, blue: 0.9, alpha: 1.0), separatorColor: UIColor.clear, font: UIFont.systemFont(ofSize: 10), fontColor: UIColor.black, padding: 0.0) } public static func darkTheme() -> SearchTextFieldTheme { - return SearchTextFieldTheme(cellHeight: 30, bgColor: UIColor (red: 0.8, green: 0.8, blue: 0.8, alpha: 0.6), borderColor: UIColor (red: 0.7, green: 0.7, blue: 0.7, alpha: 1.0), separatorColor: UIColor.clear, font: UIFont.systemFont(ofSize: 10), fontColor: UIColor.white) + return SearchTextFieldTheme(cellHeight: 30, bgColor: UIColor (red: 0.8, green: 0.8, blue: 0.8, alpha: 0.6), borderColor: UIColor (red: 0.7, green: 0.7, blue: 0.7, alpha: 1.0), separatorColor: UIColor.clear, font: UIFont.systemFont(ofSize: 10), fontColor: UIColor.white, padding: 0.0) } } From de268b2298b9e8ab8e672e73d9a269d23ff1bc84 Mon Sep 17 00:00:00 2001 From: Prathap Dodla Date: Wed, 9 Aug 2017 22:42:17 +0530 Subject: [PATCH 4/4] feature/table-corner-radius: Added support for setting corner radius to the search results table view via configuration through theme. --- Example/SearchTextField/MainViewController.swift | 2 ++ SearchTextField/Classes/SearchTextField.swift | 16 +++++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Example/SearchTextField/MainViewController.swift b/Example/SearchTextField/MainViewController.swift index e3752b1..b2466a8 100644 --- a/Example/SearchTextField/MainViewController.swift +++ b/Example/SearchTextField/MainViewController.swift @@ -69,6 +69,8 @@ class MainViewController: UITableViewController { acronymTextField.theme.placeholderColor = UIColor.lightGray //Adds padding to the table view. This leaves a visible gap between the text field and search field. acronymTextField.theme.padding = 10 + //Add corner radius to search results table view + acronymTextField.theme.cornerRadius = 5 // Max number of results - Default: No limit acronymTextField.maxNumberOfResults = 5 diff --git a/SearchTextField/Classes/SearchTextField.swift b/SearchTextField/Classes/SearchTextField.swift index f08299d..6d89420 100755 --- a/SearchTextField/Classes/SearchTextField.swift +++ b/SearchTextField/Classes/SearchTextField.swift @@ -275,7 +275,7 @@ open class SearchTextField: UITextField { var tableViewFrame = CGRect(x: 0, y: 0, width: frame.size.width - 4, height: tableHeight) tableViewFrame.origin = self.convert(tableViewFrame.origin, to: nil) tableViewFrame.origin.x += 2 - tableViewFrame.origin.y += frame.size.height + 2 + theme.padding! + tableViewFrame.origin.y += frame.size.height + 2 + theme.padding UIView.animate(withDuration: 0.2, animations: { [weak self] in self?.tableView?.frame = tableViewFrame }) @@ -288,7 +288,7 @@ open class SearchTextField: UITextField { } else { let tableHeight = min((tableView.contentSize.height), (UIScreen.main.bounds.size.height - frame.origin.y - theme.cellHeight)) UIView.animate(withDuration: 0.2, animations: { [weak self] in - self?.tableView?.frame = CGRect(x: frame.origin.x + 2, y: (frame.origin.y - tableHeight), width: frame.size.width - 4, height: tableHeight - (self?.theme.padding!)!) + self?.tableView?.frame = CGRect(x: frame.origin.x + 2, y: (frame.origin.y - tableHeight), width: frame.size.width - 4, height: tableHeight - (self?.theme.padding)!) self?.shadowView?.frame = CGRect(x: frame.origin.x + 3, y: (frame.origin.y + 3), width: frame.size.width - 6, height: 1) }) } @@ -301,7 +301,7 @@ open class SearchTextField: UITextField { } tableView.layer.borderColor = theme.borderColor.cgColor - tableView.layer.cornerRadius = 2 + tableView.layer.cornerRadius = theme.cornerRadius tableView.separatorColor = theme.separatorColor tableView.backgroundColor = theme.bgColor @@ -603,9 +603,10 @@ public struct SearchTextFieldTheme { public var font: UIFont public var fontColor: UIColor public var placeholderColor: UIColor? - public var padding: CGFloat? + public var padding: CGFloat + public var cornerRadius: CGFloat - init(cellHeight: CGFloat, bgColor:UIColor, borderColor: UIColor, separatorColor: UIColor, font: UIFont, fontColor: UIColor, padding: CGFloat) { + init(cellHeight: CGFloat, bgColor:UIColor, borderColor: UIColor, separatorColor: UIColor, font: UIFont, fontColor: UIColor, padding: CGFloat, cornerRadius: CGFloat) { self.cellHeight = cellHeight self.borderColor = borderColor self.separatorColor = separatorColor @@ -613,14 +614,15 @@ public struct SearchTextFieldTheme { self.font = font self.fontColor = fontColor self.padding = padding + self.cornerRadius = cornerRadius } public static func lightTheme() -> SearchTextFieldTheme { - return SearchTextFieldTheme(cellHeight: 30, bgColor: UIColor (red: 1, green: 1, blue: 1, alpha: 0.6), borderColor: UIColor (red: 0.9, green: 0.9, blue: 0.9, alpha: 1.0), separatorColor: UIColor.clear, font: UIFont.systemFont(ofSize: 10), fontColor: UIColor.black, padding: 0.0) + return SearchTextFieldTheme(cellHeight: 30, bgColor: UIColor (red: 1, green: 1, blue: 1, alpha: 0.6), borderColor: UIColor (red: 0.9, green: 0.9, blue: 0.9, alpha: 1.0), separatorColor: UIColor.clear, font: UIFont.systemFont(ofSize: 10), fontColor: UIColor.black, padding: 0.0, cornerRadius: 2) } public static func darkTheme() -> SearchTextFieldTheme { - return SearchTextFieldTheme(cellHeight: 30, bgColor: UIColor (red: 0.8, green: 0.8, blue: 0.8, alpha: 0.6), borderColor: UIColor (red: 0.7, green: 0.7, blue: 0.7, alpha: 1.0), separatorColor: UIColor.clear, font: UIFont.systemFont(ofSize: 10), fontColor: UIColor.white, padding: 0.0) + return SearchTextFieldTheme(cellHeight: 30, bgColor: UIColor (red: 0.8, green: 0.8, blue: 0.8, alpha: 0.6), borderColor: UIColor (red: 0.7, green: 0.7, blue: 0.7, alpha: 1.0), separatorColor: UIColor.clear, font: UIFont.systemFont(ofSize: 10), fontColor: UIColor.white, padding: 0.0, cornerRadius: 2) } }