ios Google 自动完成教程放置 api for swift

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28367436/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 04:43:08  来源:igfitidea点击:

Tutorial for Google autocomplete places api for swift

iosobjective-cxcodegoogle-mapsswift

提问by Laurenswuyts

I would like to have an autocomplete textfield that autocompletes locations for me like the one for android:

我想要一个自动完成文本字段,可以像 android 那样为我自动完成位置:

https://developers.google.com/places/training/autocomplete-android

https://developers.google.com/places/training/autocomplete-android

Does anyone know where I can find a tutorial for this or an example?

有谁知道我在哪里可以找到此教程或示例?

Thanks!

谢谢!

回答by Ashish Kakkad

Steps :

脚步 :

  1. Add the AlamofireCocoaPods in your swift project.
  2. Find your Google place API key on Google APIs Console.
  3. Add following code
  1. 在您的 swift 项目中添加AlamofireCocoaPods。
  2. 在 Google API 控制台上找到您的 Google Place API 密钥。
  3. 添加以下代码

ViewController.swift

视图控制器.swift

import UIKit

class ViewController: UIViewController {
  override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

    let gpaViewController = GooglePlacesAutocomplete(
      apiKey: "YOUR GOOGLE PLACE API KEY",
      placeType: .Address
    )

    gpaViewController.placeDelegate = self

    presentViewController(gpaViewController, animated: true, completion: nil)
  }
}

extension ViewController: GooglePlacesAutocompleteDelegate {
  func placeSelected(place: Place) {
    println(place.description)
  }

  func placeViewClosed() {
    dismissViewControllerAnimated(true, completion: nil)
  }
}

GooglePlacesAutocomplete.swift

GooglePlacesAutocomplete.swift

import UIKit
import Alamofire

enum PlaceType: Printable {
  case All
  case Geocode
  case Address
  case Establishment
  case Regions
  case Cities

  var description : String {
    switch self {
    case .All: return ""
    case .Geocode: return "geocode"
    case .Address: return "address"
    case .Establishment: return "establishment"
    case .Regions: return "regions"
    case .Cities: return "cities"
    }
  }
}

struct Place {
  let id: String
  let description: String
}

protocol GooglePlacesAutocompleteDelegate {
  func placeSelected(place: Place)
  func placeViewClosed()
}

// MARK: - GooglePlacesAutocomplete
class GooglePlacesAutocomplete: UINavigationController {
  var gpaViewController: GooglePlacesAutocompleteContainer?

  var placeDelegate: GooglePlacesAutocompleteDelegate? {
    get { return gpaViewController?.delegate }
    set { gpaViewController?.delegate = newValue }
  }

  convenience init(apiKey: String, placeType: PlaceType = .All) {
    let gpaViewController = GooglePlacesAutocompleteContainer(
      apiKey: apiKey,
      placeType: placeType
    )

    self.init(rootViewController: gpaViewController)
    self.gpaViewController = gpaViewController

    let closeButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Stop, target: self, action: "close")

    gpaViewController.navigationItem.leftBarButtonItem = closeButton
    gpaViewController.navigationItem.title = "Enter Address"
  }

  func close() {
    placeDelegate?.placeViewClosed()
  }
}

// MARK: - GooglePlaceSearchDisplayController
class GooglePlaceSearchDisplayController: UISearchDisplayController {
  override func setActive(visible: Bool, animated: Bool) {
    if active == visible { return }

    searchContentsController.navigationController?.navigationBarHidden = true
    super.setActive(visible, animated: animated)

    searchContentsController.navigationController?.navigationBarHidden = false

    if visible {
      searchBar.becomeFirstResponder()
    } else {
      searchBar.resignFirstResponder()
    }
  }
}

// MARK: - GooglePlacesAutocompleteContainer
class GooglePlacesAutocompleteContainer: UIViewController {
  var delegate: GooglePlacesAutocompleteDelegate?
  var apiKey: String?
  var places = [Place]()
  var placeType: PlaceType = .All

  convenience init(apiKey: String, placeType: PlaceType = .All) {
    self.init(nibName: "GooglePlacesAutocomplete", bundle: nil)
    self.apiKey = apiKey
    self.placeType = placeType
  }

  override func viewDidLoad() {
    super.viewDidLoad()

    let tv: UITableView? = searchDisplayController?.searchResultsTableView
    tv?.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
  }
}

// MARK: - GooglePlacesAutocompleteContainer (UITableViewDataSource / UITableViewDelegate)
extension GooglePlacesAutocompleteContainer: UITableViewDataSource, UITableViewDelegate {
  func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return places.count
  }

  func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = self.searchDisplayController?.searchResultsTableView?.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell

    // Get the corresponding candy from our candies array
    let place = self.places[indexPath.row]

    // Configure the cell
    cell.textLabel.text = place.description
    cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator

    return cell
  }

  func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    delegate?.placeSelected(self.places[indexPath.row])
  }
}

// MARK: - GooglePlacesAutocompleteContainer (UISearchDisplayDelegate)
extension GooglePlacesAutocompleteContainer: UISearchDisplayDelegate {
  func searchDisplayController(controller: UISearchDisplayController, shouldReloadTableForSearchString searchString: String!) -> Bool {
    getPlaces(searchString)
    return false
  }

  private func getPlaces(searchString: String) {
    Alamofire.request(.GET,
      "https://maps.googleapis.com/maps/api/place/autocomplete/json",
      parameters: [
        "input": searchString,
        "type": "(\(placeType.description))",
        "key": apiKey ?? ""
      ]).responseJSON { request, response, json, error in
        if let response = json as? NSDictionary {
          if let predictions = response["predictions"] as? Array<AnyObject> {
            self.places = predictions.map { (prediction: AnyObject) -> Place in
              return Place(
                id: prediction["id"] as String,
                description: prediction["description"] as String
              )
            }
          }
        }

        self.searchDisplayController?.searchResultsTableView?.reloadData()
    }
  }
}

GooglePlacesAutocomplete.xib

GooglePlacesAutocomplete.xib

GooglePlacesAutocomplete.xib

GooglePlacesAutocomplete.xib

Hope this will help others.

希望这会帮助其他人。

回答by tryKuldeepTanwar

Lightweight Solution!

轻量级解决方案!

Instead of using Google framework and Third party library to make simple requests I created a simple library where you can Make a number of Google api requests like Google Autocomplete, Google ReverseGeo, Place Informationand Pathapi for getting path between two location.

相反,使用谷歌的框架和第三方库进行简单的请求,我创建了一个简单的图书馆,在那里你可以做一些像谷歌API的请求Google AutocompleteGoogle ReverseGeoPlace InformationPath两个位置之间越来越路径API。

To use the library all you have to do is

要使用图书馆,你所要做的就是

step-1 Import GoogleApiHelperinto your project.

步骤 1 导入GoogleApiHelper到您的项目中。

step-2 Initialise GoogleApiHelper

step-2 初始化 GoogleApiHelper

GoogleApi.shared.initialiseWithKey("API_KEY")

step-3 Call the methods

step-3 调用方法

var input = GInput()
input.keyword = "San francisco"
GoogleApi.shared.callApi(input: input) { (response) in
    if let results = response.data as? [GApiResponse.Autocomplete], response.isValidFor(.autocomplete) {
        //Enjoy the Autocomplete Api
    } else { print(response.error ?? "ERROR") }
}

You can find the library here

你可以在这里找到图书馆

enter image description here

enter image description here

回答by Nrv

Using Alamofire get the autocomplete Google places result from data, you can show it in table view cell

使用 Alamofire 从数据中获取自动完成的谷歌地点结果,您可以在表格视图单元格中显示它

plist configuration

plist 配置

<key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads</key>
        <true/>
    </dict>  

Code

代码

import UIKit
    import Alamofire
    class GooglePlacesViewController: UIViewController,UISearchBarDelegate,UITableViewDataSource,UITableViewDelegate {
        @IBOutlet weak var srchLocation: UISearchBar!

        @IBOutlet weak var tblLoction: UITableView!
        var arrPlaces = NSMutableArray(capacity: 100)
        let operationQueue = OperationQueue()
        let currentLat = 51.5033640
        let currentLong = -0.1276250
        var LocationDataDelegate : LocationData! = nil
        var tblLocation : UITableView!
        var lblNodata = UILabel()

        override func viewDidLoad()
        {
             super.viewDidLoad()
            lblNodata.frame = CGRect(x: 0, y: 80, width: 
            self.view.frame.size.width, height: self.view.frame.size.height-60)
            lblNodata.text = "Please enter text to get your location"
            self.view.addSubview(lblNodata)
            srchLocation.placeholder = "Ente your location details"
            lblNodata.textAlignment = .center     
            srchLocation.delegate = self
        }
        func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
            self.beginSearching(searchText: searchText)
        }

        func beginSearching(searchText:String) {
            if searchText.characters.count == 0 {
                self.arrPlaces.removeAllObjects()
                tblLoction.isHidden = true
                lblNodata.isHidden = false
                return
            }

            operationQueue.addOperation { () -> Void in
                self.forwardGeoCoding(searchText: searchText)
            }
        }

        //MARK: - Search place from Google -
        func forwardGeoCoding(searchText:String) {
            googlePlacesResult(input: searchText) { (result) -> Void in
                let searchResult:NSDictionary = ["keyword":searchText,"results":result]
                if result.count > 0
                {
                    let features = searchResult.value(forKey: "results") as! NSArray
                    self.arrPlaces = NSMutableArray(capacity: 100)
                    print(features.count)
                    for jk in 0...features.count-1
                    {
                        let dict = features.object(at: jk) as! NSDictionary
                        self.arrPlaces.add(dict)
                    }
                    DispatchQueue.main.async(execute: {
                        if self.arrPlaces.count != 0
                        {
                            self.tblLoction.isHidden = false
                            self.lblNodata.isHidden = true
                            self.tblLoction.reloadData()
                        }
                        else
                        {
                            self.tblLoction.isHidden = true
                            self.lblNodata.isHidden = false
                            self.tblLoction.reloadData()
                        }
                    });
                }
            }
        }

        //MARK: - Google place API request -
        func googlePlacesResult(input: String, completion: @escaping (_ result: NSArray) -> Void) {
            let searchWordProtection = input.replacingOccurrences(of: " ", with: "");        if searchWordProtection.characters.count != 0 {
                let urlString = NSString(format: "https://maps.googleapis.com/maps/api/place/autocomplete/json?input=%@&types=establishment|geocode&location=%@,%@&radius=500&language=en&key= your key",input,"\(currentLocationLatitude)","\(currentLocationLongtitude)")
                print(urlString)
                let url = NSURL(string: urlString.addingPercentEscapes(using: String.Encoding.utf8.rawValue)!)
                print(url!)
                let defaultConfigObject = URLSessionConfiguration.default
                let delegateFreeSession = URLSession(configuration: defaultConfigObject, delegate: nil, delegateQueue: OperationQueue.main)
                let request = NSURLRequest(url: url! as URL)
                let task =  delegateFreeSession.dataTask(with: request as URLRequest, completionHandler:
                {
                    (data, response, error) -> Void in
                    if let data = data
                    {
                        do {
                            let jSONresult = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) as! [String:AnyObject]
                            let results:NSArray = jSONresult["predictions"] as! NSArray
                            let status = jSONresult["status"] as! String
                            if status == "NOT_FOUND" || status == "REQUEST_DENIED"
                            {
                                let userInfo:NSDictionary = ["error": jSONresult["status"]!]
                                let newError = NSError(domain: "API Error", code: 666, userInfo: userInfo as [NSObject : AnyObject])
                                let arr:NSArray = [newError]
                                completion(arr)
                                return
                            }
                            else
                            {
                                completion(results)
                            }
                        }
                        catch
                        {
                            print("json error: \(error)")
                        }
                    }
                    else if let error = error
                    {                                                              
                        print(error)
                    }
                })
                task.resume()
            }
        }
        func numberOfSections(in tableView: UITableView) -> Int {
            return 1
        }
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return arrPlaces.count
        }
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
        {
            let tblCell = tableView.dequeueReusableCell(withIdentifier: "locationCell")
            let dict = arrPlaces.object(at: indexPath.row) as! NSDictionary
            tblCell?.textLabel?.text = dict.value(forKey: "description") as? String
            tblCell?.textLabel?.numberOfLines = 0
            tblCell?.textLabel?.sizeToFit()
            return tblCell!
        }
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
        {
            if LocationDataDelegate != nil
            {
                let dict = arrPlaces.object(at: indexPath.row) as! NSDictionary
                print(dict.value(forKey: "terms") as! NSArray)
                let ArrSelected = dict.value(forKey: "terms") as! NSArray
                LocationDataDelegate.didSelectLocationData(LocationData: ArrSelected)
            }
            self.dismiss(animated: true, completion: nil)
        }

    }

回答by Anil Gupta

Here's full updated code for Google Autocomplete place API. Xcode 10.0 & Swift 4.2

这是 Google Autocomplete place API 的完整更新代码。Xcode 10.0 和 Swift 4.2

Follow this link as to Get Google API KEY.

按照此链接获取Google API KEY

After Getting the API KEY Install Cocoa Pods:

获取 API KEY 后安装 Cocoa Pods:

source 'https://github.com/CocoaPods/Specs.git'
target 'YOUR_APPLICATION_TARGET_NAME_HERE' do
  pod 'GooglePlaces'
  pod 'GooglePlacePicker'
  pod 'GoogleMaps'
end

Appdelegate File:

应用程序文件:

    import UIKit
    import GooglePlaces

    let GOOGLE_API_KEY = "AIzaSyCuZkL7bh_hIDggnJob-b0cDueWlvRgpck"

    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {

        var window: UIWindow?


        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
            // Override point for customization after application launch.
            GMSPlacesClient.provideAPIKey(GOOGLE_API_KEY)

            return true
        }

        func applicationWillResignActive(_ application: UIApplication) {
            // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
            // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
        }

        func applicationDidEnterBackground(_ application: UIApplication) {
            // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
            // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
        }

        func applicationWillEnterForeground(_ application: UIApplication) {
            // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
        }

        func applicationDidBecomeActive(_ application: UIApplication) {
            // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
        }

        func applicationWillTerminate(_ application: UIApplication) {
            // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
        }


    }

ViewController File:

视图控制器文件:

    import UIKit
    import GooglePlaces


    class ViewController: UIViewController ,CLLocationManagerDelegate{

        var placesClient: GMSPlacesClient!

        // Add a pair of UILabels in Interface Builder, and connect the outlets to these variables.
        @IBOutlet var nameLabel: UILabel!
        @IBOutlet var addressLabel: UILabel!
        let locationManager = CLLocationManager()



        var resultsViewController: GMSAutocompleteResultsViewController?
        var searchController: UISearchController?
        var resultView: UITextView?


        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view, typically from a nib.
            locationManager.delegate = self
            if CLLocationManager.authorizationStatus() == .notDetermined
            {
                locationManager.requestAlwaysAuthorization()
            }
            placesClient = GMSPlacesClient.shared()

     //       self.addToNavbar()
    //        self.addToSubview()
            self.addToPopover()

        }

        func addToNavbar(){

            resultsViewController = GMSAutocompleteResultsViewController()
            resultsViewController?.delegate = self

            searchController = UISearchController(searchResultsController: resultsViewController)
            searchController?.searchResultsUpdater = resultsViewController

            // Put the search bar in the navigation bar.
            searchController?.searchBar.sizeToFit()
            navigationItem.titleView = searchController?.searchBar

            // When UISearchController presents the results view, present it in
            // this view controller, not one further up the chain.
            definesPresentationContext = true

            // Prevent the navigation bar from being hidden when searching.
            searchController?.hidesNavigationBarDuringPresentation = false

        }

        func addToSubview(){
            resultsViewController = GMSAutocompleteResultsViewController()
            resultsViewController?.delegate = self

            searchController = UISearchController(searchResultsController: resultsViewController)
            searchController?.searchResultsUpdater = resultsViewController

            let subView = UIView(frame: CGRect(x: 0, y: 65.0, width: 350.0, height: 45.0))

            subView.addSubview((searchController?.searchBar)!)
            view.addSubview(subView)
            searchController?.searchBar.sizeToFit()
            searchController?.hidesNavigationBarDuringPresentation = false

            // When UISearchController presents the results view, present it in
            // this view controller, not one further up the chain.
            definesPresentationContext = true
        }

        func addToPopover(){

            resultsViewController = GMSAutocompleteResultsViewController()
            resultsViewController?.delegate = self

            searchController = UISearchController(searchResultsController: resultsViewController)
            searchController?.searchResultsUpdater = resultsViewController

            // Add the search bar to the right of the nav bar,
            // use a popover to display the results.
            // Set an explicit size as we don't want to use the entire nav bar.
            searchController?.searchBar.frame = (CGRect(x: 0, y: 0, width: 250.0, height: 44.0))
            navigationItem.rightBarButtonItem = UIBarButtonItem(customView: (searchController?.searchBar)!)

            // When UISearchController presents the results view, present it in
            // this view controller, not one further up the chain.
            definesPresentationContext = true

            // Keep the navigation bar visible.
            searchController?.hidesNavigationBarDuringPresentation = false
            searchController?.modalPresentationStyle = .popover
        }



        func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus)
        {
            print(status)
        }







        // Add a UIButton in Interface Builder, and connect the action to this function.
        @IBAction func getCurrentPlace(_ sender: UIButton) {

            placesClient.currentPlace(callback: { (placeLikelihoodList, error) -> Void in
                if let error = error {
                    print("Pick Place error: \(error.localizedDescription)")
                    return
                }

                self.nameLabel.text = "No current place"
                self.addressLabel.text = ""

                if let placeLikelihoodList = placeLikelihoodList {
                    print("placeLikelihoodList -- \(placeLikelihoodList)")
                    let place = placeLikelihoodList.likelihoods.first?.place
                    if let place = place {
                        self.nameLabel.text = place.name
                        self.addressLabel.text = place.formattedAddress?.components(separatedBy: ", ")
                            .joined(separator: "\n")

                        print(place.name)
                        print(place.coordinate)
                        print(place.placeID)
                        print(place.phoneNumber)
                        print(place.formattedAddress ?? "")

                    }
                }
            })
        }


    }




    //MARK: Extentions

    // Handle the user's selection.
    extension ViewController: GMSAutocompleteResultsViewControllerDelegate {
        func resultsController(_ resultsController: GMSAutocompleteResultsViewController,
                               didAutocompleteWith place: GMSPlace) {
            searchController?.isActive = false
            // Do something with the selected place.
            print("Place name: \(place.name)")
            print("Place address: \(String(describing: place.formattedAddress))")
            print("Place attributions: \(place.attributions)")
        }

        func resultsController(_ resultsController: GMSAutocompleteResultsViewController,
                               didFailAutocompleteWithError error: Error){
            // TODO: handle the error.
            print("Error: ", error.localizedDescription)
        }

        // Turn the network activity indicator on and off again.
        func didRequestAutocompletePredictions(_ viewController: GMSAutocompleteViewController) {
            UIApplication.shared.isNetworkActivityIndicatorVisible = true
        }

        func didUpdateAutocompletePredictions(_ viewController: GMSAutocompleteViewController) {
            UIApplication.shared.isNetworkActivityIndicatorVisible = false
        }
    }