Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 64 additions & 21 deletions NMFloatLabelSearchField/Classes/NMFloatLabelSearchField.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ open class NMFloatLabelSearchField: SkyFloatingLabelTextField {
/// Maximum height of the results list
open var maxResultsListHeight = 0

/// height of the search results list
open var searchResultsListHeight = 0.0

/// Indicate if this field has been interacted with yet
open var interactedWith = false

Expand All @@ -35,6 +38,13 @@ open class NMFloatLabelSearchField: SkyFloatingLabelTextField {
/// How long to wait before deciding typing has stopped
open var typingStoppedDelay = 0.8

/// to show results in full screen. Takes searchResultsListHeight to calculate search resuls screen height
open var showFullScreen: Bool = false

/// to auto select first search result on clicking done button in keyboard
open var selectOnDone: Bool = true


/// Set your custom visual theme, or just choose between pre-defined NMFloatLabelSearchFieldTheme.lightTheme() and NMFloatLabelSearchFieldTheme.darkTheme() themes
open var theme = NMFloatLabelSearchFieldTheme.lightTheme() {
didSet {
Expand Down Expand Up @@ -89,6 +99,11 @@ open class NMFloatLabelSearchField: SkyFloatingLabelTextField {

/// Start showing the default loading indicator, useful for searches that take some time.
open func showLoadingIndicator() {
guard self.rightView == nil else { return }
let indicator = UIActivityIndicatorView(style: .gray)
indicator.hidesWhenStopped = true
self.indicator = indicator
self.rightView = indicator
self.rightViewMode = .always
indicator.startAnimating()
}
Expand All @@ -98,8 +113,10 @@ open class NMFloatLabelSearchField: SkyFloatingLabelTextField {

/// Hide the default loading indicator
open func stopLoadingIndicator() {
guard let indicator = self.indicator else { return }
self.rightViewMode = .never
indicator.stopAnimating()
self.indicator = nil
}

/// When InlineMode is true, the suggestions appear in the same line than the entered string. It's useful for email domains suggestion for example.
Expand Down Expand Up @@ -135,6 +152,8 @@ open class NMFloatLabelSearchField: SkyFloatingLabelTextField {
open var tableYOffset: CGFloat = 0.0
open var tableCornerRadius: CGFloat = 2.0
open var tableBottomMargin: CGFloat = 10.0
open var tableSeperatorInset: UIEdgeInsets = .zero
open var hideShadow = false

////////////////////////////////////////////////////////////////////////
// Private implementation
Expand All @@ -147,7 +166,7 @@ open class NMFloatLabelSearchField: SkyFloatingLabelTextField {
fileprivate var timer: Timer? = nil
fileprivate var placeholderLabel: UILabel?
fileprivate static let cellIdentifier = "APNMFloatLabelSearchFieldCell"
fileprivate let indicator = UIActivityIndicatorView(style: .gray)
fileprivate var indicator: UIActivityIndicatorView?
fileprivate var maxTableViewSize: CGFloat = 0

fileprivate var filteredResults = [NMFloatLabelSearchFieldItem]()
Expand All @@ -171,6 +190,7 @@ open class NMFloatLabelSearchField: SkyFloatingLabelTextField {
open override func willMove(toWindow newWindow: UIWindow?) {
super.willMove(toWindow: newWindow)
tableView?.removeFromSuperview()
shadowView?.removeFromSuperview()
}

override open func willMove(toSuperview newSuperview: UIView?) {
Expand All @@ -194,27 +214,33 @@ open class NMFloatLabelSearchField: SkyFloatingLabelTextField {
} else {
buildSearchTableView()
}

// Create the loading indicator
indicator.hidesWhenStopped = true
self.rightView = indicator
}

override open func rightViewRect(forBounds bounds: CGRect) -> CGRect {
var rightFrame = super.rightViewRect(forBounds: bounds)
rightFrame.origin.x -= 5
rightFrame.size.width += 5
return rightFrame
}

override open func leftViewRect(forBounds bounds: CGRect) -> CGRect {
var leftFrame = super.leftViewRect(forBounds: bounds)
leftFrame.size.width += 5
return leftFrame
}


// Create the filter table and shadow view
fileprivate func buildSearchTableView() {
if let tableView = tableView, let shadowView = shadowView {
tableView.layer.masksToBounds = true
tableView.layer.borderWidth = theme.borderWidth > 0 ? theme.borderWidth : 0.5
tableView.dataSource = self
tableView.delegate = self
tableView.separatorInset = UIEdgeInsets.zero
tableView.separatorInset = self.tableSeperatorInset
tableView.tableHeaderView = resultsListHeader
if self.showFullScreen {
tableView.keyboardDismissMode = .onDrag
}
if forceRightToLeft {
if #available(iOS 9.0, *) {
tableView.semanticContentAttribute = .forceRightToLeft
Expand All @@ -224,8 +250,11 @@ open class NMFloatLabelSearchField: SkyFloatingLabelTextField {
shadowView.backgroundColor = UIColor.lightText
shadowView.layer.shadowColor = UIColor.black.cgColor
shadowView.layer.shadowOffset = CGSize.zero
shadowView.layer.shadowOpacity = 1

shadowView.layer.shadowOpacity = 0.5
shadowView.layer.shadowRadius = 4.0
shadowView.layer.masksToBounds = false

self.window?.addSubview(shadowView)
self.window?.addSubview(tableView)
} else {
tableView = UITableView(frame: CGRect.zero)
Expand Down Expand Up @@ -276,7 +305,18 @@ open class NMFloatLabelSearchField: SkyFloatingLabelTextField {
if let tableView = tableView {
guard let frame = self.superview?.convert(self.frame, to: nil) else { return }

if self.direction == .down {
if self.showFullScreen {
let tableHeight = self.searchResultsListHeight - tableYOffset
let tableWidth = frame.size.width - (2.0 * tableXOffset)
var tableViewFrame = CGRect(x: 0, y: 0, width: tableWidth, height: tableHeight)
tableViewFrame.origin = self.convert(tableViewFrame.origin, to: nil)
tableViewFrame.origin.x += tableXOffset
tableViewFrame.origin.y += frame.size.height + 2 + tableYOffset
UIView.animate(withDuration: 0.2, animations: { [weak self] in
self?.tableView?.frame = tableViewFrame
self?.shadowView?.frame = tableViewFrame
})
} else if self.direction == .down {

var tableHeight: CGFloat = 0
if keyboardIsShowing, let keyboardHeight = keyboardFrame?.size.height {
Expand All @@ -300,23 +340,18 @@ open class NMFloatLabelSearchField: SkyFloatingLabelTextField {
tableViewFrame.origin.y += frame.size.height + 2 + tableYOffset
UIView.animate(withDuration: 0.2, animations: { [weak self] in
self?.tableView?.frame = tableViewFrame
self?.shadowView?.frame = tableViewFrame
})

var shadowFrame = CGRect(x: 0, y: 0, width: frame.size.width - 6, height: 1)
shadowFrame.origin = self.convert(shadowFrame.origin, to: nil)
shadowFrame.origin.x += 3
shadowFrame.origin.y = tableView.frame.origin.y
shadowView!.frame = shadowFrame
} 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?.shadowView?.frame = CGRect(x: frame.origin.x + 3, y: (frame.origin.y + 3), width: frame.size.width - 6, height: 1)
self?.shadowView?.frame = self?.tableView?.frame ?? .zero
})
}

superview?.bringSubviewToFront(tableView)
superview?.bringSubviewToFront(shadowView!)
superview?.bringSubviewToFront(tableView)

if self.isFirstResponder {
superview?.bringSubviewToFront(self)
Expand All @@ -327,6 +362,8 @@ open class NMFloatLabelSearchField: SkyFloatingLabelTextField {
tableView.separatorColor = theme.separatorColor
tableView.backgroundColor = theme.bgColor

shadowView?.layer.cornerRadius = tableCornerRadius

tableView.reloadData()
}
}
Expand Down Expand Up @@ -396,13 +433,14 @@ open class NMFloatLabelSearchField: SkyFloatingLabelTextField {
}

@objc open func textFieldDidEndEditing() {
guard !self.showFullScreen else { return }
clearResults()
tableView?.reloadData()
placeholderLabel?.attributedText = nil
}

@objc open func textFieldDidEndEditingOnExit() {
if let firstElement = filteredResults.first {
if let firstElement = filteredResults.first, self.selectOnDone {
if let itemSelectionHandler = self.itemSelectionHandler {
itemSelectionHandler(filteredResults, 0)
}
Expand Down Expand Up @@ -486,9 +524,10 @@ open class NMFloatLabelSearchField: SkyFloatingLabelTextField {
}

// Clean filtered results
fileprivate func clearResults() {
open func clearResults() {
filteredResults.removeAll()
tableView?.removeFromSuperview()
shadowView?.removeFromSuperview()
}

// Look for Font attribute, and if it exists, adapt to the subtitle font size
Expand Down Expand Up @@ -551,8 +590,9 @@ open class NMFloatLabelSearchField: SkyFloatingLabelTextField {
extension NMFloatLabelSearchField: UITableViewDelegate, UITableViewDataSource {
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
tableView.isHidden = !interactedWith || (filteredResults.count == 0)
shadowView?.isHidden = !interactedWith || (filteredResults.count == 0)

shadowView?.isHidden = self.hideShadow ? true : (!interactedWith || (filteredResults.count == 0))

if maxNumberOfResults > 0 {
return min(filteredResults.count, maxNumberOfResults)
} else {
Expand All @@ -571,9 +611,11 @@ extension NMFloatLabelSearchField: UITableViewDelegate, UITableViewDataSource {
cell!.layoutMargins = UIEdgeInsets.zero
cell!.preservesSuperviewLayoutMargins = false
cell!.textLabel?.font = theme.font
cell!.textLabel?.numberOfLines = theme.numberOfLines
cell!.detailTextLabel?.font = UIFont(name: theme.font.fontName, size: theme.font.pointSize * fontConversionRate)
cell!.textLabel?.textColor = theme.fontColor
cell!.detailTextLabel?.textColor = theme.subtitleFontColor
cell!.detailTextLabel?.numberOfLines = theme.numberOfLines

cell!.textLabel?.text = filteredResults[(indexPath as NSIndexPath).row].title
cell!.detailTextLabel?.text = filteredResults[(indexPath as NSIndexPath).row].subtitle
Expand Down Expand Up @@ -615,6 +657,7 @@ public struct NMFloatLabelSearchFieldTheme {
public var fontColor: UIColor
public var subtitleFontColor: UIColor
public var placeholderColor: UIColor?
public var numberOfLines = 1

init(cellHeight: CGFloat, bgColor:UIColor, borderColor: UIColor, separatorColor: UIColor, font: UIFont, fontColor: UIColor, subtitleFontColor: UIColor? = nil) {
self.cellHeight = cellHeight
Expand Down