/*
* Copyright 2016 Google Inc. All rights reserved.
*
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
* file except in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
* ANY KIND, either express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
import UIKit
import GoogleMaps
import GooglePlaces
class MapViewController: UIViewController {
var locationManager: CLLocationManager!
var currentLocation: CLLocation?
var mapView: GMSMapView!
var placesClient: GMSPlacesClient!
var preciseLocationZoomLevel: Float = 15.0
var approximateLocationZoomLevel: Float = 10.0
// An array to hold the list of likely places.
var likelyPlaces: [GMSPlace] = []
// The currently selected place.
var selectedPlace: GMSPlace?
// Update the map once the user has made their selection.
@IBAction func unwindToMain(segue: UIStoryboardSegue) {
// Clear the map.
mapView.clear()
// Add a marker to the map.
if let place = selectedPlace {
let marker = GMSMarker(position: place.coordinate)
marker.title = selectedPlace?.name
marker.snippet = selectedPlace?.formattedAddress
marker.map = mapView
}
listLikelyPlaces()
}
override func viewDidLoad() {
super.viewDidLoad()
// Initialize the location manager.
locationManager = CLLocationManager()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.distanceFilter = 50
locationManager.startUpdatingLocation()
locationManager.delegate = self
placesClient = GMSPlacesClient.shared()
// A default location to use when location permission is not granted.
let defaultLocation = CLLocation(latitude: -33.869405, longitude: 151.199)
// Create a map.
let zoomLevel = locationManager.accuracyAuthorization == .fullAccuracy ? preciseLocationZoomLevel : approximateLocationZoomLevel
let camera = GMSCameraPosition.camera(withLatitude: defaultLocation.coordinate.latitude,
longitude: defaultLocation.coordinate.longitude,
zoom: zoomLevel)
mapView = GMSMapView.map(withFrame: view.bounds, camera: camera)
mapView.settings.myLocationButton = true
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
mapView.isMyLocationEnabled = true
// Add the map to the view, hide it until we've got a location update.
view.addSubview(mapView)
mapView.isHidden = true
listLikelyPlaces()
}
// Populate the array with the list of likely places.
func listLikelyPlaces() {
// Clean up from previous sessions.
likelyPlaces.removeAll()
let placeFields: GMSPlaceField = [.name, .coordinate]
placesClient.findPlaceLikelihoodsFromCurrentLocation(withPlaceFields: placeFields) { (placeLikelihoods, error) in
guard error == nil else {
// TODO: Handle the error.
print("Current Place error: \(error!.localizedDescription)")
return
}
guard let placeLikelihoods = placeLikelihoods else {
print("No places found.")
return
}
// Get likely places and add to the list.
for likelihood in placeLikelihoods {
let place = likelihood.place
self.likelyPlaces.append(place)
}
}
}
// Prepare the segue.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "segueToSelect" {
if let nextViewController = segue.destination as? PlacesViewController {
nextViewController.likelyPlaces = likelyPlaces
}
}
}
}
// Delegates to handle events for the location manager.
extension MapViewController: CLLocationManagerDelegate {
// Handle incoming location events.
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location: CLLocation = locations.last!
print("Location: \(location)")
let zoomLevel = locationManager.accuracyAuthorization == .fullAccuracy ? preciseLocationZoomLevel : approximateLocationZoomLevel
let camera = GMSCameraPosition.camera(withLatitude: location.coordinate.latitude,
longitude: location.coordinate.longitude,
zoom: zoomLevel)
if mapView.isHidden {
mapView.isHidden = false
mapView.camera = camera
} else {
mapView.animate(to: camera)
}
listLikelyPlaces()
}
// Handle authorization for the location manager.
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
// Check accuracy authorization
let accuracy = manager.accuracyAuthorization
switch accuracy {
case .fullAccuracy:
print("Location accuracy is precise.")
case .reducedAccuracy:
print("Location accuracy is not precise.")
@unknown default:
fatalError()
}
// Handle authorization status
switch status {
case .restricted:
print("Location access was restricted.")
case .denied:
print("User denied access to location.")
// Display the map using the default location.
mapView.isHidden = false
case .notDetermined:
print("Location status not determined.")
case .authorizedAlways: fallthrough
case .authorizedWhenInUse:
print("Location status is OK.")
@unknown default:
fatalError()
}
}
// Handle location manager errors.
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
locationManager.stopUpdatingLocation()
print("Error: \(error)")
}
}
/*
* Copyright 2017 Google Inc. All rights reserved.
*
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
* file except in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
* ANY KIND, either express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
import UIKit
import GooglePlaces
class PlacesViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
// An array to hold the list of possible locations.
var likelyPlaces: [GMSPlace] = []
var selectedPlace: GMSPlace?
// Cell reuse id (cells that scroll out of view can be reused).
let cellReuseIdentifier = "cell"
override func viewDidLoad() {
super.viewDidLoad()
// Register the table view cell class and its reuse id.
tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellReuseIdentifier)
// This view controller provides delegate methods and row data for the table view.
tableView.delegate = self
tableView.dataSource = self
tableView.reloadData()
}
// Pass the selected place to the new view controller.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "unwindToMain" {
if let nextViewController = segue.destination as? MapViewController {
nextViewController.selectedPlace = selectedPlace
}
}
}
}
// Respond when a user selects a place.
extension PlacesViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedPlace = likelyPlaces[indexPath.row]
performSegue(withIdentifier: "unwindToMain", sender: self)
}
// Adjust cell height to only show the first five items in the table
// (scrolling is disabled in IB).
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return self.tableView.frame.size.height/5
}
// Make table rows display at proper height if there are less than 5 items.
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
if (section == tableView.numberOfSections - 1) {
return 1
}
return 0
}
}
// Populate the table with the list of most likely places.
extension PlacesViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return likelyPlaces.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier, for: indexPath)
let collectionItem = likelyPlaces[indexPath.row]
cell.textLabel?.text = collectionItem.name
return cell
}
}
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "PlacesViewController.h"
@interface PlacesViewController () <UITableViewDataSource, UITableViewDelegate>
@property (nonatomic, weak) UITableView *tableView;
@end
@implementation PlacesViewController {
// Cell reuse id (cells that scroll out of view can be reused).
NSString *cellReuseIdentifier;
}
- (void)viewDidLoad {
[super viewDidLoad];
cellReuseIdentifier = @"cell";
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
}
#pragma mark - UITableViewDelegate
// Respond when a user selects a place.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.selectedPlace = [self.likelyPlaces objectAtIndex:indexPath.row];
[self performSegueWithIdentifier:@"unwindToMain" sender:self];
}
// Adjust cell height to only show the first five items in the table
// (scrolling is disabled in IB).
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return self.tableView.frame.size.height/5;
}
// Make table rows display at proper height if there are less than 5 items.
-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
if (section == tableView.numberOfSections - 1) {
return 1;
}
return 0;
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.likelyPlaces.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [tableView dequeueReusableCellWithIdentifier:cellReuseIdentifier forIndexPath:indexPath];
}
@end
使用 CLLocationManager 查找设备的当前位置,并在设备移至新位置时请求定期更新。本教程提供了获取设备位置所需的代码。如需了解详情,请参阅 Apple 开发者文档中的获取用户位置指南。
在类级别声明位置管理器、当前位置、地图视图、地点客户端和默认缩放级别。
Swift
var locationManager: CLLocationManager!
var currentLocation: CLLocation?
var mapView: GMSMapView!
var placesClient: GMSPlacesClient!
var preciseLocationZoomLevel: Float = 15.0
var approximateLocationZoomLevel: Float = 10.0
// An array to hold the list of likely places.
var likelyPlaces: [GMSPlace] = []
// The currently selected place.
var selectedPlace: GMSPlace?
Objective-C
// An array to hold the list of likely places.
NSMutableArray<GMSPlace *> *likelyPlaces;
// The currently selected place.
GMSPlace * _Nullable selectedPlace;
使用扩展子句添加委托,以处理营业地点管理器的事件。
Swift
// Delegates to handle events for the location manager.
extension MapViewController: CLLocationManagerDelegate {
// Handle incoming location events.
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location: CLLocation = locations.last!
print("Location: \(location)")
let zoomLevel = locationManager.accuracyAuthorization == .fullAccuracy ? preciseLocationZoomLevel : approximateLocationZoomLevel
let camera = GMSCameraPosition.camera(withLatitude: location.coordinate.latitude,
longitude: location.coordinate.longitude,
zoom: zoomLevel)
if mapView.isHidden {
mapView.isHidden = false
mapView.camera = camera
} else {
mapView.animate(to: camera)
}
listLikelyPlaces()
}
// Handle authorization for the location manager.
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
// Check accuracy authorization
let accuracy = manager.accuracyAuthorization
switch accuracy {
case .fullAccuracy:
print("Location accuracy is precise.")
case .reducedAccuracy:
print("Location accuracy is not precise.")
@unknown default:
fatalError()
}
// Handle authorization status
switch status {
case .restricted:
print("Location access was restricted.")
case .denied:
print("User denied access to location.")
// Display the map using the default location.
mapView.isHidden = false
case .notDetermined:
print("Location status not determined.")
case .authorizedAlways: fallthrough
case .authorizedWhenInUse:
print("Location status is OK.")
@unknown default:
fatalError()
}
}
// Handle location manager errors.
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
locationManager.stopUpdatingLocation()
print("Error: \(error)")
}
}
Objective-C
// Delegates to handle events for the location manager.
#pragma mark - CLLocationManagerDelegate
// Handle incoming location events.
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
CLLocation *location = locations.lastObject;
NSLog(@"Location: %@", location);
float zoomLevel = locationManager.accuracyAuthorization == CLAccuracyAuthorizationFullAccuracy ? preciseLocationZoomLevel : approximateLocationZoomLevel;
GMSCameraPosition * camera = [GMSCameraPosition cameraWithLatitude:location.coordinate.latitude
longitude:location.coordinate.longitude
zoom:zoomLevel];
if (mapView.isHidden) {
mapView.hidden = NO;
mapView.camera = camera;
} else {
[mapView animateToCameraPosition:camera];
}
[self listLikelyPlaces];
}
// Handle authorization for the location manager.
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
// Check accuracy authorization
CLAccuracyAuthorization accuracy = manager.accuracyAuthorization;
switch (accuracy) {
case CLAccuracyAuthorizationFullAccuracy:
NSLog(@"Location accuracy is precise.");
break;
case CLAccuracyAuthorizationReducedAccuracy:
NSLog(@"Location accuracy is not precise.");
break;
}
// Handle authorization status
switch (status) {
case kCLAuthorizationStatusRestricted:
NSLog(@"Location access was restricted.");
break;
case kCLAuthorizationStatusDenied:
NSLog(@"User denied access to location.");
// Display the map using the default location.
mapView.hidden = NO;
case kCLAuthorizationStatusNotDetermined:
NSLog(@"Location status not determined.");
case kCLAuthorizationStatusAuthorizedAlways:
case kCLAuthorizationStatusAuthorizedWhenInUse:
NSLog(@"Location status is OK.");
}
}
// Handle location manager errors.
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
[manager stopUpdatingLocation];
NSLog(@"Error: %@", error.localizedDescription);
}
// A default location to use when location permission is not granted.
let defaultLocation = CLLocation(latitude: -33.869405, longitude: 151.199)
// Create a map.
let zoomLevel = locationManager.accuracyAuthorization == .fullAccuracy ? preciseLocationZoomLevel : approximateLocationZoomLevel
let camera = GMSCameraPosition.camera(withLatitude: defaultLocation.coordinate.latitude,
longitude: defaultLocation.coordinate.longitude,
zoom: zoomLevel)
mapView = GMSMapView.map(withFrame: view.bounds, camera: camera)
mapView.settings.myLocationButton = true
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
mapView.isMyLocationEnabled = true
// Add the map to the view, hide it until we've got a location update.
view.addSubview(mapView)
mapView.isHidden = true
Objective-C
// A default location to use when location permission is not granted.
CLLocationCoordinate2D defaultLocation = CLLocationCoordinate2DMake(-33.869405, 151.199);
// Create a map.
float zoomLevel = locationManager.accuracyAuthorization == CLAccuracyAuthorizationFullAccuracy ? preciseLocationZoomLevel : approximateLocationZoomLevel;
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:defaultLocation.latitude
longitude:defaultLocation.longitude
zoom:zoomLevel];
mapView = [GMSMapView mapWithFrame:self.view.bounds camera:camera];
mapView.settings.myLocationButton = YES;
mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
mapView.myLocationEnabled = YES;
// Add the map to the view, hide it until we've got a location update.
[self.view addSubview:mapView];
mapView.hidden = YES;
提示用户选择他们当前的地点
使用 Places SDK for iOS 获取用户当前位置的五大可能性,并在 UITableView 中显示该列表。用户选择地点后,向地图添加标记。
获取填充 UITableView 的潜在地点列表,从中选择用户当前所处的地点。
Swift
// Populate the array with the list of likely places.
func listLikelyPlaces() {
// Clean up from previous sessions.
likelyPlaces.removeAll()
let placeFields: GMSPlaceField = [.name, .coordinate]
placesClient.findPlaceLikelihoodsFromCurrentLocation(withPlaceFields: placeFields) { (placeLikelihoods, error) in
guard error == nil else {
// TODO: Handle the error.
print("Current Place error: \(error!.localizedDescription)")
return
}
guard let placeLikelihoods = placeLikelihoods else {
print("No places found.")
return
}
// Get likely places and add to the list.
for likelihood in placeLikelihoods {
let place = likelihood.place
self.likelyPlaces.append(place)
}
}
}
Objective-C
// Populate the array with the list of likely places.
- (void) listLikelyPlaces
{
// Clean up from previous sessions.
likelyPlaces = [NSMutableArray array];
GMSPlaceField placeFields = GMSPlaceFieldName | GMSPlaceFieldCoordinate;
[placesClient findPlaceLikelihoodsFromCurrentLocationWithPlaceFields:placeFields callback:^(NSArray<GMSPlaceLikelihood *> * _Nullable likelihoods, NSError * _Nullable error) {
if (error != nil) {
// TODO: Handle the error.
NSLog(@"Current Place error: %@", error.localizedDescription);
return;
}
if (likelihoods == nil) {
NSLog(@"No places found.");
return;
}
for (GMSPlaceLikelihood *likelihood in likelihoods) {
GMSPlace *place = likelihood.place;
[likelyPlaces addObject:place];
}
}];
}
class PlacesViewController: UIViewController {
// ...
// Pass the selected place to the new view controller.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "unwindToMain" {
if let nextViewController = segue.destination as? MapViewController {
nextViewController.selectedPlace = selectedPlace
}
}
}
}
// Respond when a user selects a place.
extension PlacesViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedPlace = likelyPlaces[indexPath.row]
performSegue(withIdentifier: "unwindToMain", sender: self)
}
// Adjust cell height to only show the first five items in the table
// (scrolling is disabled in IB).
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return self.tableView.frame.size.height/5
}
// Make table rows display at proper height if there are less than 5 items.
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
if (section == tableView.numberOfSections - 1) {
return 1
}
return 0
}
}
Objective-C
@interface PlacesViewController () <UITableViewDataSource, UITableViewDelegate>
// ...
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
}
#pragma mark - UITableViewDelegate
// Respond when a user selects a place.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.selectedPlace = [self.likelyPlaces objectAtIndex:indexPath.row];
[self performSegueWithIdentifier:@"unwindToMain" sender:self];
}
// Adjust cell height to only show the first five items in the table
// (scrolling is disabled in IB).
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return self.tableView.frame.size.height/5;
}
// Make table rows display at proper height if there are less than 5 items.
-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
if (section == tableView.numberOfSections - 1) {
return 1;
}
return 0;
}
// Update the map once the user has made their selection.
@IBAction func unwindToMain(segue: UIStoryboardSegue) {
// Clear the map.
mapView.clear()
// Add a marker to the map.
if let place = selectedPlace {
let marker = GMSMarker(position: place.coordinate)
marker.title = selectedPlace?.name
marker.snippet = selectedPlace?.formattedAddress
marker.map = mapView
}
listLikelyPlaces()
}
Objective-C
// Update the map once the user has made their selection.
- (void) unwindToMain:(UIStoryboardSegue *)segue
{
// Clear the map.
[mapView clear];
// Add a marker to the map.
if (selectedPlace != nil) {
GMSMarker *marker = [GMSMarker markerWithPosition:selectedPlace.coordinate];
marker.title = selectedPlace.name;
marker.snippet = selectedPlace.formattedAddress;
marker.map = mapView;
}
[self listLikelyPlaces];
}