AutocompleteWithTextFieldController.swift 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. // Copyright 2020 Google LLC. All rights reserved.
  2. //
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
  5. // file except in compliance with the License. You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software distributed under
  10. // the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
  11. // ANY KIND, either express or implied. See the License for the specific language governing
  12. // permissions and limitations under the License.
  13. import GooglePlaces
  14. import UIKit
  15. /// Demo showing how to manually present a UITableViewController and supply it with autocomplete
  16. /// text from an arbitrary source, in this case a UITextField. Please refer to:
  17. /// https://developers.google.com/places/ios-sdk/autocomplete
  18. class AutocompleteWithTextFieldController: AutocompleteBaseViewController {
  19. private let padding: CGFloat = 20
  20. private let topPadding: CGFloat = 8
  21. private lazy var searchField: UITextField = {
  22. let searchField = UITextField(frame: .zero)
  23. searchField.translatesAutoresizingMaskIntoConstraints = false
  24. searchField.borderStyle = .none
  25. if #available(iOS 13.0, *) {
  26. searchField.textColor = .label
  27. searchField.backgroundColor = .systemBackground
  28. } else {
  29. searchField.backgroundColor = .white
  30. }
  31. searchField.placeholder = NSLocalizedString(
  32. "Demo.Content.Autocomplete.EnterTextPrompt",
  33. comment: "Prompt to enter text for autocomplete demo")
  34. searchField.autocorrectionType = .no
  35. searchField.keyboardType = .default
  36. searchField.returnKeyType = .done
  37. searchField.clearButtonMode = .whileEditing
  38. searchField.contentVerticalAlignment = .center
  39. searchField.addTarget(self, action: #selector(textFieldChanged), for: .editingChanged)
  40. return searchField
  41. }()
  42. private lazy var resultsController: UITableViewController = {
  43. return UITableViewController(style: .plain)
  44. }()
  45. private lazy var tableDataSource: GMSAutocompleteTableDataSource = {
  46. let tableDataSource = GMSAutocompleteTableDataSource()
  47. tableDataSource.tableCellBackgroundColor = .white
  48. tableDataSource.delegate = self
  49. if let config = autocompleteConfiguration {
  50. tableDataSource.autocompleteFilter = config.autocompleteFilter
  51. tableDataSource.placeFields = config.placeFields
  52. }
  53. return tableDataSource
  54. }()
  55. override func viewDidLoad() {
  56. super.viewDidLoad()
  57. view.backgroundColor = .white
  58. searchField.delegate = self
  59. view.addSubview(searchField)
  60. NSLayoutConstraint.activate([
  61. searchField.topAnchor.constraint(
  62. equalTo: self.topLayoutGuide.bottomAnchor, constant: topPadding),
  63. searchField.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: padding),
  64. searchField.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -padding),
  65. ])
  66. tableDataSource.delegate = self
  67. resultsController.tableView.delegate = tableDataSource
  68. resultsController.tableView.dataSource = tableDataSource
  69. // Add the results controller
  70. guard let resultView = resultsController.view else { return }
  71. resultView.translatesAutoresizingMaskIntoConstraints = false
  72. resultView.alpha = 0
  73. view.addSubview(resultView)
  74. NSLayoutConstraint.activate([
  75. resultView.topAnchor.constraint(equalTo: searchField.bottomAnchor, constant: 0),
  76. resultView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
  77. resultView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
  78. resultView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
  79. ])
  80. }
  81. @objc func textFieldChanged(sender: UIControl) {
  82. guard let textField = sender as? UITextField else { return }
  83. tableDataSource.sourceTextHasChanged(textField.text)
  84. }
  85. func dismissResultView() {
  86. resultsController.willMove(toParent: nil)
  87. UIView.animate(
  88. withDuration: 0.5,
  89. animations: {
  90. self.resultsController.view.alpha = 0
  91. }
  92. ) { (_) in
  93. self.resultsController.view.removeFromSuperview()
  94. self.resultsController.removeFromParent()
  95. }
  96. }
  97. }
  98. extension AutocompleteWithTextFieldController: UITextFieldDelegate {
  99. func textFieldDidBeginEditing(_ textField: UITextField) {
  100. addChild(resultsController)
  101. resultsController.tableView.reloadData()
  102. UIView.animate(
  103. withDuration: 0.5,
  104. animations: {
  105. self.resultsController.view.alpha = 1
  106. }
  107. ) { (_) in
  108. self.resultsController.didMove(toParent: self)
  109. }
  110. }
  111. func textFieldShouldReturn(_ textField: UITextField) -> Bool {
  112. textField.resignFirstResponder()
  113. return false
  114. }
  115. func textFieldShouldClear(_ textField: UITextField) -> Bool {
  116. dismissResultView()
  117. textField.resignFirstResponder()
  118. textField.text = ""
  119. tableDataSource.clearResults()
  120. return false
  121. }
  122. }
  123. extension AutocompleteWithTextFieldController: GMSAutocompleteTableDataSourceDelegate {
  124. func tableDataSource(
  125. _ tableDataSource: GMSAutocompleteTableDataSource, didAutocompleteWith place: GMSPlace
  126. ) {
  127. dismissResultView()
  128. searchField.resignFirstResponder()
  129. searchField.isHidden = true
  130. autocompleteDidSelectPlace(place)
  131. }
  132. func tableDataSource(
  133. _ tableDataSource: GMSAutocompleteTableDataSource, didFailAutocompleteWithError error: Error
  134. ) {
  135. dismissResultView()
  136. searchField.resignFirstResponder()
  137. searchField.isHidden = true
  138. autocompleteDidFail(error)
  139. }
  140. func didRequestAutocompletePredictions(for tableDataSource: GMSAutocompleteTableDataSource) {
  141. resultsController.tableView.reloadData()
  142. }
  143. func didUpdateAutocompletePredictions(for tableDataSource: GMSAutocompleteTableDataSource) {
  144. resultsController.tableView.reloadData()
  145. }
  146. }