Skip to content

Instantly share code, notes, and snippets.

@AshvinGudaliya
Last active April 10, 2023 07:02
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save AshvinGudaliya/264e2ff5f505ff1c4d8b3f2a24c61779 to your computer and use it in GitHub Desktop.
Save AshvinGudaliya/264e2ff5f505ff1c4d8b3f2a24c61779 to your computer and use it in GitHub Desktop.
A simple subclass of UITextField for getting auto complete place search from Google Places.
//
// AGAutocompletePlaceTextfield.swift
// AGAutocompletePlaceTextfield
//
// Created by Arpit Jain on 28/07/17.
// Copyright © 2017 Arpit Jain. All rights reserved.
//
import UIKit
import GooglePlaces
class AGAutocompletePlaceTextfield: UITextField , UITextFieldDelegate {
//MARK: - PROPERTIES
struct AGFilterPlace {
let id: String
let name: String
}
let placesClient = GMSPlacesClient()
/// Instance of autoCompleteTableView
fileprivate var tableView: UITableView?
/// Gives the array of autoCompletePlacesData
open var autoCompletePlacesData = [AGFilterPlace]()
/// Gives the selected place and indexPath
open var selectedPlace: ((GMSPlace) -> ())?
/// Font for the places data
open var autoCompleteTextFont = UIFont.systemFont(ofSize: 12)
/// Color of the places data
open var autoCompleteTextColor = UIColor.black
/// Used to set the height of cell for each suggestions
open var autoCompleteCellHeight: CGFloat = 44.0
/// The maximum visible suggestion
open var maxAutoCompleteDataCount = 5
/// Used to set your own preferred separator inset
open var autoCompleteSeparatorInset = UIEdgeInsets.zero
/// Hides autoCompleteTableView after selecting a place
open var hidesWhenSelected = true
/// Shows autoCompletePlacesData with formatting
open var highLightTypeTextedEnabled: Bool?
/// Define attributes for highlighted text
open var highLightTypeTextedAttributes: [NSAttributedStringKey: Any]?
/// The autoCompleteTableView height
open var autoCompleteTableHeight: CGFloat?{
didSet{
redrawTable()
}
}
/// this is the x margin for table view from textfield
open var autoCompleteTableMargin = CGFloat()
//MARK: - INIT FUNCTIONS
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
open override func awakeFromNib() {
super.awakeFromNib()
commonInit()
setupAutocompleteTable(superview!)
}
override func layoutSubviews() {
super.layoutSubviews()
commonInit()
setupAutocompleteTable(superview!)
}
open override func willMove(toSuperview newSuperview: UIView?) {
super.willMove(toSuperview: newSuperview)
commonInit()
setupAutocompleteTable(newSuperview!)
}
fileprivate func commonInit(){
tableView?.isHidden = true
highLightTypeTextedEnabled = false
highLightTypeTextedAttributes = [NSAttributedStringKey.foregroundColor: UIColor.black]
highLightTypeTextedAttributes![NSAttributedStringKey.font] = UIFont.boldSystemFont(ofSize: 12)
self.clearButtonMode = .always
self.addTarget(self, action: #selector(AGAutocompletePlaceTextfield.textFieldDidChange), for: .editingChanged)
self.addTarget(self, action: #selector(AGAutocompletePlaceTextfield.textFieldDidEndEditing), for: .editingDidEnd)
}
fileprivate func setupAutocompleteTable(_ view:UIView){
autoCompleteTableMargin = 10.0
tableView = UITableView(frame: CGRect(x: self.frame.origin.x + autoCompleteTableMargin/2, y: self.frame.origin.y + self.frame.height, width: (self.frame.width - autoCompleteTableMargin), height: 30.0))
tableView?.dataSource = self
tableView?.delegate = self
tableView?.rowHeight = autoCompleteCellHeight
tableView?.isHidden = true
tableView?.layer.borderColor = UIColor.lightGray.cgColor
tableView?.layer.borderWidth = 0.5
tableView?.layer.zPosition = CGFloat(Float.greatestFiniteMagnitude)
view.addSubview(tableView!)
autoCompleteTableHeight = 200.0
}
fileprivate func redrawTable(){
if let tableView = tableView, let autoCompleteTableHeight = autoCompleteTableHeight {
var newFrame = tableView.frame
newFrame.size.height = autoCompleteTableHeight
tableView.frame = newFrame
}
}
//MARK: - Private Methodss
fileprivate func showHighlightedTypedText(aStr : NSString) -> NSAttributedString {
let attrs = [NSAttributedStringKey.foregroundColor: autoCompleteTextColor, NSAttributedStringKey.font: autoCompleteTextFont]
let range = aStr.range(of: text!, options: .caseInsensitive)
let attString = NSMutableAttributedString(string: aStr as String, attributes: attrs)
attString.addAttributes(highLightTypeTextedAttributes!, range: range)
autoCompleteTextColor = UIColor.gray
return attString
}
//MARK: - AJAutoCompleteTextfieldDelegate
@objc func textFieldDidChange(){
placesClient.autocompleteQuery(text ?? "", bounds: nil, filter: nil, callback: { (results, error) in
DispatchQueue.main.async
{
self.autoCompletePlacesData.removeAll()
if results != nil {
for result in results!{
if let placeId = result.placeID {
self.autoCompletePlacesData.append(AGFilterPlace(id: placeId , name: result.attributedFullText.string))
}
}
}
if self.autoCompletePlacesData.count != 0{
self.tableView?.isHidden = false
if self.autoCompletePlacesData.count < self.maxAutoCompleteDataCount{
self.autoCompleteTableHeight = self.tableView?.contentSize.height
}else{
self.autoCompleteTableHeight = 200
}
self.tableView?.reloadData()
}else{
self.tableView?.isHidden = true
}
}
})
}
func GetPlaceDataByPlaceID(pPlaceID: String) {
//pPlaceID = "ChIJXbmAjccVrjsRlf31U1ZGpDM"
self.placesClient.lookUpPlaceID(pPlaceID, callback: { (place, error) -> Void in
if let error = error {
print("lookup place id query error: \(error.localizedDescription)")
return
}
if let place = place {
DispatchQueue.main.async {
self.tableView?.isHidden = self.hidesWhenSelected
self.selectedPlace?(place)
}
}
else {
print("No place details for \(pPlaceID)")
}
})
}
}
//MARK: - UITableViewDataSource & UITableViewDelegate
extension AGAutocompletePlaceTextfield: UITableViewDataSource, UITableViewDelegate {
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return autoCompletePlacesData.count
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "autocompleteCellIdentifier"
var cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)
if cell == nil{
cell = UITableViewCell(style: .default, reuseIdentifier: cellIdentifier)
}
if highLightTypeTextedEnabled!{
cell?.textLabel?.attributedText = showHighlightedTypedText(aStr: autoCompletePlacesData[indexPath.row].name as NSString)
}else{
cell?.textLabel?.font = autoCompleteTextFont
cell?.textLabel?.textColor = autoCompleteTextColor
cell?.textLabel?.text = autoCompletePlacesData[indexPath.row].name
}
cell?.textLabel?.numberOfLines = 0
cell?.contentView.gestureRecognizers = nil
return cell!
}
public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
if let selectedText = cell?.textLabel?.text {
self.GetPlaceDataByPlaceID(pPlaceID: autoCompletePlacesData[indexPath.row].id)
self.text = selectedText
self.resignFirstResponder()
}
}
public func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if cell.responds(to: #selector(setter: UITableViewCell.separatorInset)){
cell.separatorInset = autoCompleteSeparatorInset
}
if cell.responds(to: #selector(setter: UIView.preservesSuperviewLayoutMargins)){
cell.preservesSuperviewLayoutMargins = false
}
if cell.responds(to: #selector(setter: UIView.layoutMargins)){
cell.layoutMargins = autoCompleteSeparatorInset
}
}
public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return autoCompleteCellHeight
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment