Tự động hoàn thành địa điểm

Chọn nền tảng: Android iOS JavaScript Dịch vụ web

Dịch vụ tự động điền trong SDK Địa điểm dành cho iOS trả về thông tin dự đoán về địa điểm để phản hồi cụm từ tìm kiếm của người dùng. Khi người dùng nhập, dịch vụ tự động hoàn thành sẽ trả về các đề xuất cho địa điểm như doanh nghiệp, địa chỉ, mã cộng và điểm yêu thích.

Bạn có thể thêm tính năng tự động hoàn thành vào ứng dụng theo các cách sau:

Thêm thành phần điều khiển giao diện người dùng tự động hoàn thành

Thành phần điều khiển giao diện người dùng tự động hoàn thành là một hộp thoại tìm kiếm có chức năng tự động hoàn thành tích hợp. Khi người dùng nhập cụm từ tìm kiếm, thành phần điều khiển sẽ hiển thị danh sách các địa điểm được dự đoán để người dùng chọn. Khi người dùng chọn một địa điểm, một thực thể GMSPlace sẽ được trả về. Sau đó, ứng dụng của bạn có thể sử dụng thực thể này để lấy thông tin chi tiết về địa điểm đã chọn.

Bạn có thể thêm thành phần điều khiển giao diện người dùng tự động hoàn thành vào ứng dụng theo các cách sau:

Thêm thành phần điều khiển toàn màn hình

Sử dụng chế độ điều khiển toàn màn hình khi bạn muốn có ngữ cảnh phương thức, trong đó giao diện người dùng tự động hoàn thành sẽ tạm thời thay thế giao diện người dùng của ứng dụng cho đến khi người dùng đưa ra lựa chọn. Chức năng này do lớp GMSAutocompleteViewController cung cấp. Khi người dùng chọn một địa điểm, ứng dụng của bạn sẽ nhận được lệnh gọi lại.

Cách thêm thành phần điều khiển toàn màn hình vào ứng dụng:

  1. Tạo một thành phần trên giao diện người dùng trong ứng dụng chính để chạy thành phần điều khiển tự động hoàn tất trên giao diện người dùng, ví dụ: trình xử lý thao tác chạm trên UIButton.
  2. Triển khai giao thức GMSAutocompleteViewControllerDelegate trong trình kiểm soát khung hiển thị mẹ.
  3. Tạo một thực thể của GMSAutocompleteViewController và chỉ định trình điều khiển thành phần hiển thị mẹ làm thuộc tính uỷ quyền.
  4. Tạo GMSPlaceField để xác định các loại dữ liệu địa điểm cần trả về.
  5. Thêm GMSAutocompleteFilter để ràng buộc truy vấn với một loại địa điểm cụ thể.
  6. Trình bày GMSAutocompleteViewController bằng [self presentViewController...].
  7. Xử lý lựa chọn của người dùng trong phương thức uỷ quyền didAutocompleteWithPlace.
  8. Đóng trình điều khiển trong các phương thức uỷ quyền didAutocompleteWithPlace, didFailAutocompleteWithErrorwasCancelled.

Ví dụ sau đây minh hoạ một cách có thể để khởi chạy GMSAutocompleteViewController để phản hồi khi người dùng nhấn vào một nút.

Swift

import UIKit
import GooglePlaces

class ViewController: UIViewController {

  override func viewDidLoad() {
    makeButton()
  }

  // Present the Autocomplete view controller when the button is pressed.
  @objc func autocompleteClicked(_ sender: UIButton) {
    let autocompleteController = GMSAutocompleteViewController()
    autocompleteController.delegate = self

    // Specify the place data types to return.
    let fields: GMSPlaceField = GMSPlaceField(rawValue: UInt(GMSPlaceField.name.rawValue) |
      UInt(GMSPlaceField.placeID.rawValue))!
    autocompleteController.placeFields = fields

    // Specify a filter.
    let filter = GMSAutocompleteFilter()
    filter.types = [.address]
    autocompleteController.autocompleteFilter = filter

    // Display the autocomplete view controller.
    present(autocompleteController, animated: true, completion: nil)
  }

  // Add a button to the view.
  func makeButton() {
    let btnLaunchAc = UIButton(frame: CGRect(x: 5, y: 150, width: 300, height: 35))
    btnLaunchAc.backgroundColor = .blue
    btnLaunchAc.setTitle("Launch autocomplete", for: .normal)
    btnLaunchAc.addTarget(self, action: #selector(autocompleteClicked), for: .touchUpInside)
    self.view.addSubview(btnLaunchAc)
  }

}

extension ViewController: GMSAutocompleteViewControllerDelegate {

  // Handle the user's selection.
  func viewController(_ viewController: GMSAutocompleteViewController, didAutocompleteWith place: GMSPlace) {
    print("Place name: \(place.name)")
    print("Place ID: \(place.placeID)")
    print("Place attributions: \(place.attributions)")
    dismiss(animated: true, completion: nil)
  }

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

  // User canceled the operation.
  func wasCancelled(_ viewController: GMSAutocompleteViewController) {
    dismiss(animated: true, completion: nil)
  }

  // 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
  }

}

Objective-C

#import "ViewController.h"
@import GooglePlaces;

@interface ViewController () <GMSAutocompleteViewControllerDelegate>

@end

@implementation ViewController {
  GMSAutocompleteFilter *_filter;
}

-   (void)viewDidLoad {
  [super viewDidLoad];
  [self makeButton];
}

  // Present the autocomplete view controller when the button is pressed.
-   (void)autocompleteClicked {
  GMSAutocompleteViewController *acController = [[GMSAutocompleteViewController alloc] init];
  acController.delegate = self;

  // Specify the place data types to return.
  GMSPlaceField fields = (GMSPlaceFieldName | GMSPlaceFieldPlaceID);
  acController.placeFields = fields;

  // Specify a filter.
  _filter = [[GMSAutocompleteFilter alloc] init];
  _filter.types = @[ kGMSPlaceTypeBank ];
  acController.autocompleteFilter = _filter;

  // Display the autocomplete view controller.
  [self presentViewController:acController animated:YES completion:nil];
}

  // Add a button to the view.
-   (void)makeButton{
  UIButton *btnLaunchAc = [UIButton buttonWithType:UIButtonTypeCustom];
  [btnLaunchAc addTarget:self
             action:@selector(autocompleteClicked) forControlEvents:UIControlEventTouchUpInside];
  [btnLaunchAc setTitle:@"Launch autocomplete" forState:UIControlStateNormal];
  btnLaunchAc.frame = CGRectMake(5.0, 150.0, 300.0, 35.0);
  btnLaunchAc.backgroundColor = [UIColor blueColor];
  [self.view addSubview:btnLaunchAc];
}

  // Handle the user's selection.
-   (void)viewController:(GMSAutocompleteViewController *)viewController
didAutocompleteWithPlace:(GMSPlace *)place {
  [self dismissViewControllerAnimated:YES completion:nil];
  // Do something with the selected place.
  NSLog(@"Place name %@", place.name);
  NSLog(@"Place ID %@", place.placeID);
  NSLog(@"Place attributions %@", place.attributions.string);
}

-   (void)viewController:(GMSAutocompleteViewController *)viewController
didFailAutocompleteWithError:(NSError *)error {
  [self dismissViewControllerAnimated:YES completion:nil];
  // TODO: handle the error.
  NSLog(@"Error: %@", [error description]);
}

  // User canceled the operation.
-   (void)wasCancelled:(GMSAutocompleteViewController *)viewController {
  [self dismissViewControllerAnimated:YES completion:nil];
}

  // Turn the network activity indicator on and off again.
-   (void)didRequestAutocompletePredictions:(GMSAutocompleteViewController *)viewController {
  [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
}

-   (void)didUpdateAutocompletePredictions:(GMSAutocompleteViewController *)viewController {
  [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}

@end

Thêm bộ điều khiển kết quả

Sử dụng bộ điều khiển kết quả khi bạn muốn kiểm soát nhiều hơn giao diện người dùng nhập văn bản. Trình điều khiển kết quả sẽ tự động bật/tắt chế độ hiển thị danh sách kết quả dựa trên tiêu điểm giao diện người dùng đầu vào.

Cách thêm trình điều khiển kết quả vào ứng dụng:

  1. Tạo GMSAutocompleteResultsViewController.
    1. Triển khai giao thức GMSAutocompleteResultsViewControllerDelegate trong trình điều khiển thành phần hiển thị mẹ và chỉ định trình điều khiển thành phần hiển thị mẹ làm thuộc tính uỷ quyền.
  2. Tạo một đối tượng UISearchController, truyền vào GMSAutocompleteResultsViewController làm đối số của trình điều khiển kết quả.
  3. Đặt GMSAutocompleteResultsViewController làm thuộc tính searchResultsUpdater của UISearchController.
  4. Thêm searchBar cho UISearchController vào giao diện người dùng của ứng dụng.
  5. Xử lý lựa chọn của người dùng trong phương thức uỷ quyền didAutocompleteWithPlace.

Có một số cách để đặt thanh tìm kiếm của UISearchController vào giao diện người dùng của ứng dụng:

Thêm thanh tìm kiếm vào thanh điều hướng

Ví dụ về mã sau đây minh hoạ cách thêm trình điều khiển kết quả, thêm searchBar vào thanh điều hướng và xử lý lựa chọn của người dùng:

Swift

class ViewController: UIViewController {

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

  override func viewDidLoad() {
    super.viewDidLoad()

    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
  }
}

// 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: \(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
  }
}

Objective-C

-   (void)viewDidLoad {
  _resultsViewController = [[GMSAutocompleteResultsViewController alloc] init];
  _resultsViewController.delegate = self;

  _searchController = [[UISearchController alloc]
                       initWithSearchResultsController:_resultsViewController];
  _searchController.searchResultsUpdater = _resultsViewController;

  // Put the search bar in the navigation bar.
  [_searchController.searchBar sizeToFit];
  self.navigationItem.titleView = _searchController.searchBar;

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

  // Prevent the navigation bar from being hidden when searching.
  _searchController.hidesNavigationBarDuringPresentation = NO;
}

// Handle the user's selection.
-   (void)resultsController:(GMSAutocompleteResultsViewController *)resultsController
  didAutocompleteWithPlace:(GMSPlace *)place {
    _searchController.active = NO;
    // Do something with the selected place.
    NSLog(@"Place name %@", place.name);
    NSLog(@"Place address %@", place.formattedAddress);
    NSLog(@"Place attributions %@", place.attributions.string);
}

-   (void)resultsController:(GMSAutocompleteResultsViewController *)resultsController
didFailAutocompleteWithError:(NSError *)error {
  [self dismissViewControllerAnimated:YES completion:nil];
  // TODO: handle the error.
  NSLog(@"Error: %@", [error description]);
}

// Turn the network activity indicator on and off again.
-   (void)didRequestAutocompletePredictionsForResultsController:
    (GMSAutocompleteResultsViewController *)resultsController {
  [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
}

-   (void)didUpdateAutocompletePredictionsForResultsController:
    (GMSAutocompleteResultsViewController *)resultsController {
  [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}

Thêm thanh tìm kiếm vào đầu thành phần hiển thị

Ví dụ về mã sau đây cho thấy cách thêm searchBar vào đầu thành phần hiển thị.

Swift

import UIKit
import GooglePlaces

class ViewController: UIViewController {

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

  override func viewDidLoad() {
    super.viewDidLoad()

    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
  }
}

// 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: \(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(forResultsController resultsController: GMSAutocompleteResultsViewController) {
    UIApplication.shared.isNetworkActivityIndicatorVisible = true
  }

  func didUpdateAutocompletePredictions(forResultsController resultsController: GMSAutocompleteResultsViewController) {
    UIApplication.shared.isNetworkActivityIndicatorVisible = false
  }
}

Objective-C

-   (void)viewDidLoad {
    [super viewDidLoad];

    _resultsViewController = [[GMSAutocompleteResultsViewController alloc] init];
    _resultsViewController.delegate = self;

    _searchController = [[UISearchController alloc]
                             initWithSearchResultsController:_resultsViewController];
    _searchController.searchResultsUpdater = _resultsViewController;

    UIView *subView = [[UIView alloc] initWithFrame:CGRectMake(0, 65.0, 250, 50)];

    [subView addSubview:_searchController.searchBar];
    [_searchController.searchBar sizeToFit];
    [self.view addSubview:subView];

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

// Handle the user's selection.
-   (void)resultsController:(GMSAutocompleteResultsViewController *)resultsController
didAutocompleteWithPlace:(GMSPlace *)place {
  [self dismissViewControllerAnimated:YES completion:nil];
  // Do something with the selected place.
  NSLog(@"Place name %@", place.name);
  NSLog(@"Place address %@", place.formattedAddress);
  NSLog(@"Place attributions %@", place.attributions.string);
}

-   (void)resultsController:(GMSAutocompleteResultsViewController *)resultsController
didFailAutocompleteWithError:(NSError *)error {
  [self dismissViewControllerAnimated:YES completion:nil];
  // TODO: handle the error.
  NSLog(@"Error: %@", [error description]);
}

// Turn the network activity indicator on and off again.
-   (void)didRequestAutocompletePredictionsForResultsController:
    (GMSAutocompleteResultsViewController *)resultsController {
  [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
}

-   (void)didUpdateAutocompletePredictionsForResultsController:
    (GMSAutocompleteResultsViewController *)resultsController {
  [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}

Theo mặc định, UISearchController sẽ ẩn thanh điều hướng khi trình bày (bạn có thể tắt tính năng này). Trong trường hợp thanh điều hướng hiển thị và mờ, UISearchController sẽ không đặt vị trí chính xác.

Hãy sử dụng mã sau đây để khắc phục vấn đề:

Swift

navigationController?.navigationBar.translucent = false
searchController?.hidesNavigationBarDuringPresentation = false

// This makes the view area include the nav bar even though it is opaque.
// Adjust the view placement down.
self.extendedLayoutIncludesOpaqueBars = true
self.edgesForExtendedLayout = .top

Objective-C

self.navigationController.navigationBar.translucent = NO;
_searchController.hidesNavigationBarDuringPresentation = NO;

// This makes the view area include the nav bar even though it is opaque.
// Adjust the view placement down.
self.extendedLayoutIncludesOpaqueBars = YES;
self.edgesForExtendedLayout = UIRectEdgeTop;

Thêm thanh tìm kiếm bằng kết quả bật lên

Ví dụ về mã sau đây cho thấy cách đặt thanh tìm kiếm ở bên phải thanh điều hướng và hiển thị kết quả trong một cửa sổ bật lên.

Swift

import UIKit
import GooglePlaces

class ViewController: UIViewController {

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

  override func viewDidLoad() {
    super.viewDidLoad()

    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
  }
}
// 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: \(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(forResultsController resultsController: GMSAutocompleteResultsViewController) {
    UIApplication.shared.isNetworkActivityIndicatorVisible = true
  }

  func didUpdateAutocompletePredictions(forResultsController resultsController: GMSAutocompleteResultsViewController) {
    UIApplication.shared.isNetworkActivityIndicatorVisible = false
  }
}

Objective-C

-   (void)viewDidLoad {
  [super viewDidLoad];

  _resultsViewController = [[GMSAutocompleteResultsViewController alloc] init];
  _resultsViewController.delegate = self;

  _searchController = [[UISearchController alloc]
                           initWithSearchResultsController:_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 = CGRectMake(0, 0, 250.0f, 44.0f);
  self.navigationItem.rightBarButtonItem =
  [[UIBarButtonItem alloc] initWithCustomView:_searchController.searchBar];

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

  // Keep the navigation bar visible.
  _searchController.hidesNavigationBarDuringPresentation = NO;

  _searchController.modalPresentationStyle = UIModalPresentationPopover;
}

// Handle the user's selection.
-   (void)resultsController:(GMSAutocompleteResultsViewController *)resultsController
didAutocompleteWithPlace:(GMSPlace *)place {
  [self dismissViewControllerAnimated:YES completion:nil];
  NSLog(@"Place name %@", place.name);
  NSLog(@"Place address %@", place.formattedAddress);
  NSLog(@"Place attributions %@", place.attributions.string);
}

-   (void)resultsController:(GMSAutocompleteResultsViewController *)resultsController
didFailAutocompleteWithError:(NSError *)error {
  [self dismissViewControllerAnimated:YES completion:nil];
  // TODO: handle the error.
  NSLog(@"Error: %@", [error description]);
}

// Turn the network activity indicator on and off again.
-   (void)didRequestAutocompletePredictionsForResultsController:
    (GMSAutocompleteResultsViewController *)resultsController {
  [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
}

-   (void)didUpdateAutocompletePredictionsForResultsController:
    (GMSAutocompleteResultsViewController *)resultsController {
  [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}

Sử dụng nguồn dữ liệu bảng

Nếu ứng dụng của bạn có giao diện người dùng văn bản tìm kiếm tuỳ chỉnh, bạn có thể sử dụng lớp GMSAutocompleteTableDataSource để điều khiển chế độ xem theo bảng hiển thị kết quả trên trình điều khiển thành phần hiển thị.

Cách sử dụng GMSAutocompleteTableDataSource làm nguồn dữ liệu và uỷ quyền của UITableView trong trình điều khiển thành phần hiển thị:

  1. Triển khai các giao thức GMSAutocompleteTableDataSourceDelegateUISearchBarDelegate trong trình điều khiển thành phần hiển thị.
  2. Tạo một thực thể GMSAutocompleteTableDataSource và chỉ định trình điều khiển khung hiển thị làm thuộc tính uỷ quyền.
  3. Đặt GMSAutocompleteTableDataSource làm nguồn dữ liệu và uỷ quyền các thuộc tính của thực thể UITableView trên trình điều khiển thành phần hiển thị.
  4. Trong trình xử lý cho hoạt động nhập văn bản tìm kiếm, hãy gọi sourceTextHasChanged trên GMSAutocompleteTableDataSource.
    1. Xử lý lựa chọn của người dùng trong phương thức uỷ quyền didAutocompleteWithPlace.
  5. Đóng trình điều khiển trong các phương thức uỷ quyền didAutocompleteWithPlace, didFailAutocompleteWithError, wasCancelled.

Ví dụ về mã sau đây minh hoạ cách sử dụng lớp GMSAutocompleteTableDataSource để điều khiển chế độ xem theo bảng của UIViewController khi UISearchBar được thêm riêng biệt.

Swift

// 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 GooglePlaces
import UIKit

class PlaceAutocompleteViewController: UIViewController {

  private var tableView: UITableView!
  private var tableDataSource: GMSAutocompleteTableDataSource!

  override func viewDidLoad() {
    super.viewDidLoad()

    let searchBar = UISearchBar(frame: CGRect(x: 0, y: 20, width: self.view.frame.size.width, height: 44.0))
    searchBar.delegate = self
    view.addSubview(searchBar)

    tableDataSource = GMSAutocompleteTableDataSource()
    tableDataSource.delegate = self

    tableView = UITableView(frame: CGRect(x: 0, y: 64, width: self.view.frame.size.width, height: self.view.frame.size.height - 44))
    tableView.delegate = tableDataSource
    tableView.dataSource = tableDataSource

    view.addSubview(tableView)
  }
}

extension PlaceAutocompleteViewController: UISearchBarDelegate {
  func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    // Update the GMSAutocompleteTableDataSource with the search text.
    tableDataSource.sourceTextHasChanged(searchText)
  }
}

extension PlaceAutocompleteViewController: GMSAutocompleteTableDataSourceDelegate {
  func didUpdateAutocompletePredictions(for tableDataSource: GMSAutocompleteTableDataSource) {
    // Turn the network activity indicator off.
    UIApplication.shared.isNetworkActivityIndicatorVisible = false
    // Reload table data.
    tableView.reloadData()
  }

  func didRequestAutocompletePredictions(for tableDataSource: GMSAutocompleteTableDataSource) {
    // Turn the network activity indicator on.
    UIApplication.shared.isNetworkActivityIndicatorVisible = true
    // Reload table data.
    tableView.reloadData()
  }

  func tableDataSource(_ tableDataSource: GMSAutocompleteTableDataSource, didAutocompleteWith place: GMSPlace) {
    // Do something with the selected place.
    print("Place name: \(place.name)")
    print("Place address: \(place.formattedAddress)")
    print("Place attributions: \(place.attributions)")
  }

  func tableDataSource(_ tableDataSource: GMSAutocompleteTableDataSource, didFailAutocompleteWithError error: Error) {
    // Handle the error.
    print("Error: \(error.localizedDescription)")
  }

  func tableDataSource(_ tableDataSource: GMSAutocompleteTableDataSource, didSelect prediction: GMSAutocompletePrediction) -> Bool {
    return true
  }
}

      

Objective-C

// 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 "PlaceAutocompleteViewController.h"
@import GooglePlaces;
@import UIKit;

@interface PlaceAutocompleteViewController () <GMSAutocompleteTableDataSourceDelegate, UISearchBarDelegate>

@end

@implementation PlaceAutocompleteViewController {
  UITableView *tableView;
  GMSAutocompleteTableDataSource *tableDataSource;
}

- (void)viewDidLoad {
  [super viewDidLoad];

  UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 20, self.view.frame.size.width, 44)];
  searchBar.delegate = self;

  [self.view addSubview:searchBar];

  tableDataSource = [[GMSAutocompleteTableDataSource alloc] init];
  tableDataSource.delegate = self;

  tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 64, self.view.frame.size.width, self.view.frame.size.height - 44)];
  tableView.delegate = tableDataSource;
  tableView.dataSource = tableDataSource;

  [self.view addSubview:tableView];
}

#pragma mark - GMSAutocompleteTableDataSourceDelegate

- (void)didUpdateAutocompletePredictionsForTableDataSource:(GMSAutocompleteTableDataSource *)tableDataSource {
  // Turn the network activity indicator off.
  UIApplication.sharedApplication.networkActivityIndicatorVisible = NO;

  // Reload table data.
  [tableView reloadData];
}

- (void)didRequestAutocompletePredictionsForTableDataSource:(GMSAutocompleteTableDataSource *)tableDataSource {
  // Turn the network activity indicator on.
  UIApplication.sharedApplication.networkActivityIndicatorVisible = YES;

  // Reload table data.
  [tableView reloadData];
}

- (void)tableDataSource:(GMSAutocompleteTableDataSource *)tableDataSource didAutocompleteWithPlace:(GMSPlace *)place {
  // Do something with the selected place.
  NSLog(@"Place name: %@", place.name);
  NSLog(@"Place address: %@", place.formattedAddress);
  NSLog(@"Place attributions: %@", place.attributions);
}

- (void)tableDataSource:(GMSAutocompleteTableDataSource *)tableDataSource didFailAutocompleteWithError:(NSError *)error {
  // Handle the error
  NSLog(@"Error %@", error.description);
}

- (BOOL)tableDataSource:(GMSAutocompleteTableDataSource *)tableDataSource didSelectPrediction:(GMSAutocompletePrediction *)prediction {
  return YES;
}

#pragma mark - UISearchBarDelegate

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
  // Update the GMSAutocompleteTableDataSource with the search text.
  [tableDataSource sourceTextHasChanged:searchText];
}

@end

      

Tuỳ chỉnh màu văn bản và màu nền

Bạn có thể đặt màu của tất cả văn bản và nền trong thành phần điều khiển giao diện người dùng tự động hoàn thành để tiện ích khớp với giao diện trực quan của ứng dụng một cách chặt chẽ hơn. Có hai cách để đặt màu điều khiển giao diện người dùng:

  • Bằng cách sử dụng giao thức UIAppearance tích hợp sẵn của iOS để tạo kiểu cho các thành phần điều khiển trên giao diện người dùng trên toàn hệ thống nếu có thể. Các chế độ cài đặt này áp dụng cho nhiều, nhưng không phải tất cả, các thành phần điều khiển trên giao diện người dùng.
  • Bằng cách sử dụng các phương thức SDK trên các lớp tiện ích để đặt các thuộc tính không được giao thức UIAppearance hỗ trợ.

Thông thường, ứng dụng của bạn sẽ sử dụng một số tổ hợp của giao thức UIAppearance và các phương thức SDK. Sơ đồ sau đây cho biết những phần tử có thể được tạo kiểu:

Màu sắc của thành phần điều khiển trên giao diện người dùng tự động hoàn thành

Bảng sau đây liệt kê tất cả các thành phần trên giao diện người dùng và cho biết cách tạo kiểu cho từng thành phần (giao thức UIAppearance hoặc phương thức SDK).

Phần tử trên giao diện người dùng Phương thức Hướng dẫn định phong cách
Màu sắc của thanh điều hướng (nền) Giao thức UIAppearance Gọi setBarTintColor trên proxy UINavigationBar.
Màu sắc phủ trên Thanh điều hướng (con trỏ văn bản trên thanh tìm kiếm và nút Huỷ) Giao thức UIAppearance Gọi setTintColor trên proxy UINavigationBar.
Màu văn bản trên Thanh tìm kiếm Giao thức UIAppearance Đặt NSForegroundColorAttributeName trong searchBarTextAttributes.
Màu phủ của thanh tìm kiếm Không áp dụng Thanh tìm kiếm có màu trong suốt và sẽ hiển thị dưới dạng phiên bản có bóng của Thanh điều hướng.
Màu văn bản giữ chỗ trên thanh tìm kiếm (văn bản tìm kiếm mặc định) Giao thức UIAppearance Đặt NSForegroundColorAttributeName trong placeholderAttributes.
Văn bản chính (cũng áp dụng cho văn bản lỗi và thông báo) Phương thức SDK Gọi cho primaryTextColor.
Đánh dấu văn bản chính Phương thức SDK Gọi cho primaryTextHighlightColor.
Văn bản phụ Phương thức SDK Gọi cho secondaryTextColor.
Lỗi và văn bản thông báo Phương thức SDK Gọi cho primaryTextColor.
Nền ô trong bảng Phương thức SDK Gọi cho tableCellBackgroundColor.
Màu của dấu phân cách ô trong bảng Phương thức SDK Gọi cho tableCellSeparatorColor.
Nút "Thử lại" Phương thức SDK Gọi cho tintColor.
Chỉ báo hoạt động (vòng quay tiến trình) Giao thức UIAppearance Gọi setColor trên proxy UIActivityIndicatorView.
Biểu trưng "Powered by Google" (Dựa trên Google), hình ảnh đám mây buồn Không áp dụng Phiên bản màu trắng hoặc màu xám được tự động chọn dựa trên độ tương phản của nền.
Biểu tượng kính lúp và biểu tượng xoá văn bản trong trường văn bản Thanh tìm kiếm Không áp dụng Để tạo kiểu, hãy thay thế hình ảnh mặc định bằng hình ảnh có màu mong muốn.

Sử dụng giao thức UIAppearance

Bạn có thể sử dụng giao thức UIAppearance để lấy proxy giao diện cho một thành phần trên giao diện người dùng nhất định, sau đó bạn có thể sử dụng proxy này để đặt màu cho thành phần trên giao diện người dùng. Khi bạn thực hiện một nội dung sửa đổi, tất cả các thực thể của một phần tử giao diện người dùng nhất định sẽ bị ảnh hưởng. Ví dụ: ví dụ sau đây sẽ thay đổi màu văn bản của các lớp UITextField thành màu xanh lục khi các lớp này nằm trong UISearchBar:

[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil]
    setDefaultTextAttributes:@{NSForegroundColorAttributeName:[UIColor greenColor]}];

Để biết thêm thông tin về cách xác định giá trị màu, hãy tham khảo Tài liệu tham khảo về lớp UIColor.

Các đoạn mã sau đây cho thấy tất cả các lệnh proxy mà bạn cần sử dụng để định kiểu mọi thứ trong thành phần điều khiển giao diện người dùng tự động hoàn thành ở chế độ toàn màn hình. Thêm mã này vào phương thức didFinishLaunchingWithOptions trong Appdelegate.m:

// Define some colors.
UIColor *darkGray = [UIColor darkGrayColor];
UIColor *lightGray = [UIColor lightGrayColor];

// Navigation bar background.
[[UINavigationBar appearance] setBarTintColor:darkGray];
[[UINavigationBar appearance] setTintColor:lightGray];

// Color of typed text in the search bar.
NSDictionary *searchBarTextAttributes = @{
                                          NSForegroundColorAttributeName: lightGray,
                                          NSFontAttributeName : [UIFont systemFontOfSize:[UIFont systemFontSize]]
                                          };
[UITextField appearanceWhenContainedInInstancesOfClasses:@[[UISearchBar class]]]
    .defaultTextAttributes = searchBarTextAttributes;

// Color of the placeholder text in the search bar prior to text entry.
NSDictionary *placeholderAttributes = @{
                                        NSForegroundColorAttributeName: lightGray,
                                        NSFontAttributeName : [UIFont systemFontOfSize:[UIFont systemFontSize]]
                                        };

// Color of the default search text.
// NOTE: In a production scenario, "Search" would be a localized string.
NSAttributedString *attributedPlaceholder =
[[NSAttributedString alloc] initWithString:@"Search"
                                attributes:placeholderAttributes];
[UITextField appearanceWhenContainedInInstancesOfClasses:@[[UISearchBar class]]]
    .attributedPlaceholder = attributedPlaceholder;

// Color of the in-progress spinner.
[[UIActivityIndicatorView appearance] setColor:lightGray];

// To style the two image icons in the search bar (the magnifying glass
// icon and the 'clear text' icon), replace them with different images.
[[UISearchBar appearance] setImage:[UIImage imageNamed:@"custom_clear_x_high"]
                  forSearchBarIcon:UISearchBarIconClear
                            state:UIControlStateHighlighted];
[[UISearchBar appearance] setImage:[UIImage imageNamed:@"custom_clear_x"]
                  forSearchBarIcon:UISearchBarIconClear
                            state:UIControlStateNormal];
[[UISearchBar appearance] setImage:[UIImage imageNamed:@"custom_search"]
                    forSearchBarIcon:UISearchBarIconSearch
                            state:UIControlStateNormal];

// Color of selected table cells.
UIView *selectedBackgroundView = [[UIView alloc] init];
selectedBackgroundView.backgroundColor = [UIColor lightGrayColor];
[UITableViewCell appearanceWhenContainedIn:[GMSAutocompleteViewController class], nil]
    .selectedBackgroundView = selectedBackgroundView;

Thiết lập thuộc tính kiểu điều khiển giao diện người dùng

Một tập hợp con các thành phần điều khiển giao diện người dùng có các thuộc tính không chịu ảnh hưởng của giao thức UIAppearance, do đó phải được đặt trực tiếp. Ví dụ về mã sau đây cho thấy cách xác định màu nền trước và màu nền, đồng thời áp dụng các màu đó cho một thực thể điều khiển giao diện người dùng có tên là acController. Thêm mã này vào phương thức onLaunchClicked trong ViewController.m:

UIColor *darkGray = [UIColor darkGrayColor];
UIColor *lightGray = [UIColor lightGrayColor];

acController.secondaryTextColor = [UIColor colorWithWhite:1.0f alpha:0.5f];
acController.primaryTextColor = lightGray;
acController.primaryTextHighlightColor = [UIColor grayColor];
acController.tableCellBackgroundColor = darkGray;
acController.tableCellSeparatorColor = lightGray;
acController.tintColor = lightGray;

Nhận thông tin dự đoán về địa điểm theo phương thức lập trình

Bạn có thể tạo giao diện người dùng tìm kiếm tuỳ chỉnh thay cho giao diện người dùng do tiện ích tự động hoàn thành cung cấp. Để làm được việc này, ứng dụng của bạn phải nhận thông tin dự đoán về địa điểm bằng cách lập trình. Ứng dụng của bạn có thể nhận được danh sách tên địa điểm và/hoặc địa chỉ được dự đoán theo một trong những cách sau:

Đang gọi cho GMSPlacesClient findAutocompletePredictionsFromQuery:

Để nhận danh sách tên địa điểm và/hoặc địa chỉ được dự đoán, trước tiên, hãy tạo bản sao GMSPlacesClient, sau đó gọi phương thức GMSPlacesClient findAutocompletePredictionsFromQuery: bằng các tham số sau:

  • Chuỗi autocompleteQuery chứa văn bản do người dùng nhập.
  • Một GMSAutocompleteSessionToken dùng để xác định từng phiên riêng lẻ. Ứng dụng của bạn phải truyền cùng một mã thông báo cho mỗi lệnh gọi yêu cầu tự động hoàn thành, sau đó truyền mã thông báo đó cùng với Mã địa điểm trong lệnh gọi tiếp theo đến fetchPlacefromPlaceID: để truy xuất Thông tin chi tiết về địa điểm cho địa điểm mà người dùng đã chọn.
  • Một GMSAutocompleteFilter đến:
    • Bỏ qua hoặc giới hạn kết quả ở một khu vực cụ thể.
    • Hạn chế kết quả ở một loại địa điểm cụ thể.
    • Đối tượng GMSPlaceLocationBias/Restriction làm lệch kết quả đến một khu vực cụ thể được chỉ định theo giới hạn vĩ độ và kinh độ.
  • Phương thức gọi lại để xử lý kết quả dự đoán được trả về.

Các ví dụ về mã dưới đây cho thấy lệnh gọi đến findAutocompletePredictionsFromQuery:.

Swift

/**
 *   Create a new session token. Be sure to use the same token for calling
 *   findAutocompletePredictions, as well as the subsequent place details request.
 *   This ensures that the user's query and selection are billed as a single session.
 */
let token = GMSAutocompleteSessionToken.init()

// Create a type filter.
let filter = GMSAutocompleteFilter()
filter.types = [.bank]
filter.locationBias = GMSPlaceRectangularLocationOption( northEastBounds,
                                   southWestBounds);

placesClient?.findAutocompletePredictions(fromQuery: "cheesebu",

                                          filter: filter,
                                          sessionToken: token,
                                          callback: { (results, error) in
    if let error = error {
      print("Autocomplete error: \(error)")
      return
    }
    if let results = results {
      for result in results {
        print("Result \(result.attributedFullText) with placeID \(result.placeID)")
      }
    }
})

Objective-C

/**
 *   Create a new session token. Be sure to use the same token for calling
 *   findAutocompletePredictionsFromQuery:, as well as the subsequent place details request.
 *   This ensures that the user's query and selection are billed as a single session.
 */
GMSAutocompleteSessionToken *token = [[GMSAutocompleteSessionToken alloc] init];

// Create a type filter.
GMSAutocompleteFilter *_filter = [[GMSAutocompleteFilter alloc] init];
_filter.types = @[ kGMSPlaceTypeBank ];

[_placesClient findAutocompletePredictionsFromQuery:@"cheesebu"
filter:_filter sessionToken:token callback:^(NSArray<GMSAutocompletePrediction *> * _Nullable results, NSError * _Nullable error) {
  if (error != nil) {
    NSLog(@"An error occurred %@", [error localizedDescription]);
    return;
  }
  if (results != nil) {
    for (GMSAutocompletePrediction *result in results) {
      NSLog(@"Result %@ with PlaceID %@", result.attributedFullText, result.placeID);
    }
  }
}];

API gọi phương thức gọi lại đã chỉ định, truyền vào một mảng các đối tượng GMSAutocompletePrediction.

Mỗi đối tượng GMSAutocompletePrediction chứa những thông tin sau:

  • attributedFullText – Toàn bộ văn bản của nội dung dự đoán, ở dạng NSAttributedString. Ví dụ: "Nhà hát Opera Sydney, Sydney, New South Wales, Úc". Mỗi dải văn bản khớp với dữ liệu đầu vào của người dùng đều có một thuộc tính là kGMSAutocompleteMatchAttribute. Bạn có thể sử dụng thuộc tính này để làm nổi bật văn bản trùng khớp trong cụm từ tìm kiếm của người dùng, chẳng hạn như trong ví dụ bên dưới.
  • placeID – Mã địa điểm của địa điểm được dự đoán. Mã địa điểm là một giá trị nhận dạng dạng văn bản giúp xác định duy nhất một địa điểm. Để biết thêm thông tin về mã địa điểm, hãy xem bài viết Tổng quan về mã địa điểm.
  • distanceMeters – Khoảng cách theo đường thẳng từ origin đã chỉ định đến đích. Nếu bạn không đặt thuộc tính origin, hệ thống sẽ không trả về giá trị khoảng cách.

Ví dụ về mã sau đây minh hoạ cách làm nổi bật bằng văn bản in đậm các phần kết quả khớp với văn bản trong truy vấn của người dùng, bằng cách sử dụng enumerateAttribute:

Swift

let regularFont = UIFont.systemFont(ofSize: UIFont.labelFontSize)
let boldFont = UIFont.boldSystemFont(ofSize: UIFont.labelFontSize)

let bolded = prediction.attributedFullText.mutableCopy() as! NSMutableAttributedString
bolded.enumerateAttribute(kGMSAutocompleteMatchAttribute, in: NSMakeRange(0, bolded.length), options: []) {
  (value, range: NSRange, stop: UnsafeMutablePointer<ObjCBool>) -> Void in
    let font = (value == nil) ? regularFont : boldFont
    bolded.addAttribute(NSFontAttributeName, value: font, range: range)
}

label.attributedText = bolded
    

Objective-C

UIFont *regularFont = [UIFont systemFontOfSize:[UIFont labelFontSize]];
UIFont *boldFont = [UIFont boldSystemFontOfSize:[UIFont labelFontSize]];

NSMutableAttributedString *bolded = [prediction.attributedFullText mutableCopy];
[bolded enumerateAttribute:kGMSAutocompleteMatchAttribute
                   inRange:NSMakeRange(0, bolded.length)
                   options:0
                usingBlock:^(id value, NSRange range, BOOL *stop) {
                  UIFont *font = (value == nil) ? regularFont : boldFont;
                  [bolded addAttribute:NSFontAttributeName value:font range:range];
                }];

label.attributedText = bolded;
    

Sử dụng trình tìm nạp

Nếu muốn tạo chế độ tự động hoàn thành của riêng mình từ đầu, bạn có thể sử dụng GMSAutocompleteFetcher. Phương thức này sẽ gói phương thức autocompleteQuery trên GMSPlacesClient. Trình tìm nạp sẽ điều tiết các yêu cầu, chỉ trả về kết quả cho văn bản tìm kiếm được nhập gần đây nhất. Lớp này không cung cấp thành phần giao diện người dùng.

Để triển khai GMSAutocompleteFetcher, hãy làm theo các bước sau:

  1. Triển khai giao thức GMSAutocompleteFetcherDelegate.
  2. Tạo đối tượng GMSAutocompleteFetcher.
  3. Gọi sourceTextHasChanged trên trình tìm nạp khi người dùng nhập.
  4. Xử lý các dự đoán và lỗi bằng phương thức giao thức didAutcompleteWithPredictionsdidFailAutocompleteWithError.

Ví dụ về mã sau đây minh hoạ cách sử dụng trình tìm nạp để nhập dữ liệu của người dùng và hiển thị các kết quả trùng khớp về địa điểm trong chế độ xem văn bản. Đã bỏ qua chức năng chọn địa điểm. FetcherSampleViewController bắt nguồn từ UIViewController trong FetcherSampleViewController.h.

Swift

import UIKit
import GooglePlaces

class ViewController: UIViewController {

  var textField: UITextField?
  var resultText: UITextView?
  var fetcher: GMSAutocompleteFetcher?

  override func viewDidLoad() {
    super.viewDidLoad()

    view.backgroundColor = .white
    edgesForExtendedLayout = []

    // Set bounds to inner-west Sydney Australia.
    let neBoundsCorner = CLLocationCoordinate2D(latitude: -33.843366,
                                                longitude: 151.134002)
    let swBoundsCorner = CLLocationCoordinate2D(latitude: -33.875725,
                                                longitude: 151.200349)

    // Set up the autocomplete filter.
    let filter = GMSAutocompleteFilter()
    filter.locationRestriction = GMSPlaceRectangularLocationOption(neBoundsCorner, swBoundsCorner)

    // Create a new session token.
    let token: GMSAutocompleteSessionToken = GMSAutocompleteSessionToken.init()

    // Create the fetcher.
    fetcher = GMSAutocompleteFetcher(bounds: nil, filter: filter)
    fetcher?.delegate = self
    fetcher?.provide(token)

    textField = UITextField(frame: CGRect(x: 5.0, y: 10.0,
                                          width: view.bounds.size.width - 5.0,
                                          height: 64.0))
    textField?.autoresizingMask = .flexibleWidth
    textField?.addTarget(self, action: #selector(textFieldDidChange(textField:)),
                         for: .editingChanged)
    let placeholder = NSAttributedString(string: "Type a query...")

    textField?.attributedPlaceholder = placeholder

    resultText = UITextView(frame: CGRect(x: 0, y: 65.0,
                                          width: view.bounds.size.width,
                                          height: view.bounds.size.height - 65.0))
    resultText?.backgroundColor = UIColor(white: 0.95, alpha: 1.0)
    resultText?.text = "No Results"
    resultText?.isEditable = false

    self.view.addSubview(textField!)
    self.view.addSubview(resultText!)
  }

  @objc func textFieldDidChange(textField: UITextField) {
    fetcher?.sourceTextHasChanged(textField.text!)
  }

}

extension ViewController: GMSAutocompleteFetcherDelegate {
  func didAutocomplete(with predictions: [GMSAutocompletePrediction]) {
    let resultsStr = NSMutableString()
    for prediction in predictions {
      resultsStr.appendFormat("\n Primary text: %@\n", prediction.attributedPrimaryText)
      resultsStr.appendFormat("Place ID: %@\n", prediction.placeID)
    }

    resultText?.text = resultsStr as String
  }

  func didFailAutocompleteWithError(_ error: Error) {
    resultText?.text = error.localizedDescription
  }
}

Objective-C

#import "FetcherSampleViewController.h"
#import <GooglePlaces/GooglePlaces.h>

@interface FetcherSampleViewController () <GMSAutocompleteFetcherDelegate>

@end

@implementation FetcherSampleViewController {
  UITextField *_textField;
  UITextView *_resultText;
  GMSAutocompleteFetcher* _fetcher;
}

-   (void)viewDidLoad {
  [super viewDidLoad];

  self.view.backgroundColor = [UIColor whiteColor];
  self.edgesForExtendedLayout = UIRectEdgeNone;

  // Set bounds to inner-west Sydney Australia.
  CLLocationCoordinate2D neBoundsCorner = CLLocationCoordinate2DMake(-33.843366, 151.134002);
  CLLocationCoordinate2D swBoundsCorner = CLLocationCoordinate2DMake(-33.875725, 151.200349);

  GMSAutocompleteFilter *autocompleteFilter = [[GMSAutocompleteFilter alloc] init];
  autocompleteFilter.locationRestriction =
        GMSPlaceRectangularLocationOption(neBoundsCorner, swBoundsCorner);

  // Create the fetcher.
  _fetcher = [[GMSAutocompleteFetcher alloc] initWithBounds:nil
                                                     filter:filter];
  _fetcher.delegate = self;

  // Set up the UITextField and UITextView.
  _textField = [[UITextField alloc] initWithFrame:CGRectMake(5.0f,
                                                             0,
                                                             self.view.bounds.size.width - 5.0f,
                                                             44.0f)];
  _textField.autoresizingMask = UIViewAutoresizingFlexibleWidth;
  [_textField addTarget:self
                 action:@selector(textFieldDidChange:)
       forControlEvents:UIControlEventEditingChanged];
  _resultText =[[UITextView alloc] initWithFrame:CGRectMake(0,
                                                            45.0f,
                                                            self.view.bounds.size.width,
                                                            self.view.bounds.size.height - 45.0f)];
  _resultText.backgroundColor = [UIColor colorWithWhite:0.95f alpha:1.0f];
  _resultText.text = @"No Results";
  _resultText.editable = NO;
  [self.view addSubview:_textField];
  [self.view addSubview:_resultText];
}

-   (void)textFieldDidChange:(UITextField *)textField {
  NSLog(@"%@", textField.text);
  [_fetcher sourceTextHasChanged:textField.text];
}

#pragma mark - GMSAutocompleteFetcherDelegate
-   (void)didAutocompleteWithPredictions:(NSArray *)predictions {
  NSMutableString *resultsStr = [NSMutableString string];
  for (GMSAutocompletePrediction *prediction in predictions) {
      [resultsStr appendFormat:@"%@\n", [prediction.attributedPrimaryText string]];
  }
  _resultText.text = resultsStr;
}

-   (void)didFailAutocompleteWithError:(NSError *)error {
  _resultText.text = [NSString stringWithFormat:@"%@", error.localizedDescription];
}

@end

Mã thông báo phiên

Mã thông báo phiên nhóm các giai đoạn truy vấn và lựa chọn của một lượt tìm kiếm tự động hoàn thành của người dùng thành một phiên riêng biệt cho mục đích thanh toán. Phiên bắt đầu khi người dùng bắt đầu nhập truy vấn và kết thúc khi họ chọn một địa điểm. Mỗi phiên có thể có nhiều truy vấn, theo sau là một lựa chọn địa điểm. Sau khi một phiên kết thúc, mã thông báo sẽ không còn hợp lệ nữa; ứng dụng của bạn phải tạo một mã thông báo mới cho mỗi phiên. Bạn nên sử dụng mã thông báo phiên cho tất cả các phiên tự động hoàn thành theo phương thức lập trình (khi bạn sử dụng trình điều khiển toàn màn hình hoặc trình điều khiển kết quả, API sẽ tự động xử lý việc này).

SDK Địa điểm dành cho iOS sử dụng GMSAutocompleteSessionToken để xác định từng phiên. Ứng dụng của bạn phải truyền mã thông báo phiên mới khi bắt đầu mỗi phiên mới, sau đó truyền cùng một mã thông báo đó cùng với Mã địa điểm trong lệnh gọi tiếp theo đến fetchPlacefromPlaceID: để truy xuất Thông tin chi tiết về địa điểm cho địa điểm mà người dùng đã chọn.

Tìm hiểu thêm về mã thông báo phiên.

Sử dụng mã sau để tạo mã thông báo phiên mới:

let token: GMSAutocompleteSessionToken = GMSAutocompleteSessionToken.init()

Hạn mức sử dụng

Hiển thị thông tin phân bổ trong ứng dụng

  • Nếu ứng dụng của bạn sử dụng dịch vụ tự động điền theo phương thức lập trình, thì giao diện người dùng của bạn phải hiển thị thông tin ghi công "Do Google cung cấp" hoặc xuất hiện trong bản đồ mang thương hiệu Google.
  • Nếu ứng dụng của bạn sử dụng thành phần điều khiển giao diện người dùng tự động hoàn thành, thì bạn không cần làm gì thêm (mục phân bổ bắt buộc sẽ hiển thị theo mặc định).
  • Nếu truy xuất và hiển thị thông tin bổ sung về địa điểm sau khi tìm một địa điểm theo mã, bạn cũng phải hiển thị thông tin ghi công của bên thứ ba.

Để biết thêm thông tin, hãy xem tài liệu về phân bổ.

Kiểm soát chỉ báo hoạt động mạng

Để kiểm soát chỉ báo hoạt động mạng trong thanh trạng thái của ứng dụng, bạn phải triển khai các phương thức uỷ quyền không bắt buộc thích hợp cho lớp tự động hoàn thành mà bạn đang sử dụng và tự bật và tắt chỉ báo mạng.

  • Đối với GMSAutocompleteViewController, bạn phải triển khai các phương thức uỷ quyền didRequestAutocompletePredictions:didUpdateAutocompletePredictions:.
  • Đối với GMSAutocompleteResultsViewController, bạn phải triển khai các phương thức uỷ quyền didRequestAutocompletePredictionsForResultsController:didUpdateAutocompletePredictionsForResultsController:.
  • Đối với GMSAutocompleteTableDataSource, bạn phải triển khai các phương thức uỷ quyền didRequestAutocompletePredictionsForTableDataSource:didUpdateAutocompletePredictionsForTableDataSource:.

Bằng cách triển khai các phương thức này và đặt [UIApplication sharedApplication].networkActivityIndicatorVisible thành YESNO tương ứng, thanh trạng thái sẽ khớp chính xác với giao diện người dùng tự động hoàn thành.

Giới hạn kết quả tự động hoàn thành

Bạn có thể đặt chế độ kiểm soát giao diện người dùng tự động hoàn thành để giới hạn kết quả ở một khu vực địa lý cụ thể và/hoặc lọc kết quả theo một hoặc nhiều loại địa điểm hoặc theo một hoặc nhiều quốc gia cụ thể. Để ràng buộc kết quả, bạn có thể làm như sau:

  • Để ưu tiên (thiên vị) kết quả trong vùng đã xác định, hãy đặt locationBias trên GMSAutocompleteFilter (một số kết quả bên ngoài vùng đã xác định vẫn có thể được trả về). Nếu bạn cũng đặt locationRestriction, thì locationBias sẽ bị bỏ qua.
  • Để chỉ hiển thị (hạn chế) kết quả trong khu vực đã xác định, hãy đặt locationRestriction trên GMSAutocompleteFilter (chỉ kết quả trong khu vực đã xác định mới được trả về).

    • Lưu ý: Quy định hạn chế này chỉ áp dụng cho toàn bộ tuyến đường, kết quả tổng hợp nằm ngoài giới hạn hình chữ nhật có thể được trả về dựa trên một tuyến đường trùng lặp với quy định hạn chế về vị trí.
  • Để chỉ trả về kết quả tuân thủ một loại địa điểm cụ thể, hãy đặt types trên GMSAutocompleteFilter, (ví dụ: chỉ định TypeFilter.ADDRESS sẽ khiến tiện ích chỉ trả về kết quả có địa chỉ chính xác).

  • Để chỉ trả về kết quả trong tối đa 5 quốc gia được chỉ định, hãy đặt countries trên GMSAutocompleteFilter.

Kết quả thiên vị một khu vực cụ thể

Để ưu tiên (thiên vị) kết quả trong vùng đã xác định, hãy đặt locationBias trên GMSAutocompleteFilter như sau:

northEast = CLLocationCoordinate2DMake(39.0, -95.0);  southWest =
CLLocationCoordinate2DMake(37.5, -100.0);  GMSAutocompleteFilter *filter =
[[GMSAutocompleteFilter alloc] init];  filter.locationBias =
GMSPlaceRectangularLocationOption(northEast, southWest);

Hạn chế kết quả ở một khu vực cụ thể

Để chỉ hiển thị (hạn chế) kết quả trong khu vực đã xác định, hãy đặt locationRestriction trên GMSAutocompleteFilter như sau:

northEast = CLLocationCoordinate2DMake(39.0, -95.0);  southWest =
CLLocationCoordinate2DMake(37.5, -100.0);  GMSAutocompleteFilter *filter =
[[GMSAutocompleteFilter alloc] init];  filter.locationRestriction =
GMSPlaceRectangularLocationOption(northEast, southWest);

Lọc kết quả theo quốc gia

Để lọc kết quả trong tối đa 5 quốc gia được chỉ định, hãy đặt countries trên GMSAutocompleteFilter như sau:

GMSAutocompleteFilter *filter = [[GMSAutocompleteFilter alloc] init];
filter.countries = @[ @"au", @"nz" ];

Lọc kết quả theo loại địa điểm hoặc bộ sưu tập loại

Hạn chế kết quả ở một loại hoặc tập hợp loại nhất định bằng cách đặt thuộc tính types của GMSAutoCompleteFilter. Sử dụng thuộc tính này để chỉ định các bộ lọc được liệt kê trong Bảng 1, 2 và 3 về Loại trung tâm. Nếu bạn không chỉ định loại nào, thì tất cả các loại sẽ được trả về.

Cách chỉ định bộ lọc loại hoặc bộ lọc bộ sưu tập loại:

  • Sử dụng thuộc tính types để chỉ định tối đa 5 giá trị type (loại) trong Bảng 1 và Bảng 2 hiển thị trên Place Types (Loại địa điểm). Các giá trị loại được xác định bằng các hằng số trong GMSPlaceType.

  • Sử dụng thuộc tính types để chỉ định một bộ sưu tập loại trong Bảng 3 hiển thị trên Loại địa điểm. Các giá trị tập hợp kiểu được xác định bằng các hằng số trong GMSPlaceType.

    Yêu cầu chỉ được phép chứa một loại trong Bảng 3. Nếu chỉ định một giá trị trong Bảng 3, bạn không thể chỉ định một giá trị trong Bảng 1 hoặc Bảng 2. Nếu bạn làm như vậy, lỗi sẽ xảy ra.

Ví dụ: để chỉ trả về những kết quả tuân thủ một loại địa điểm cụ thể, hãy đặt types trên GMSAutocompleteFilter. Ví dụ sau đây cho thấy cách đặt bộ lọc để chỉ trả về kết quả có địa chỉ chính xác:

GMSAutocompleteFilter *filter = [[GMSAutocompleteFilter alloc] init];
filter.types = @[ kGMSPlaceTypeAirport, kGMSPlaceTypeAmusementPark ];

Tối ưu hoá tính năng Tự động hoàn thành của Place

Phần này mô tả các phương pháp hay nhất để giúp bạn khai thác tối đa dịch vụ Tự động hoàn thành địa điểm.

Dưới đây là một số nguyên tắc chung:

  • Cách nhanh nhất để phát triển giao diện người dùng hoạt động là sử dụng Tiện ích tự động hoàn thành API Maps JavaScript, Tiện ích tự động hoàn thành SDK Địa điểm dành cho Android hoặc Chế độ điều khiển giao diện người dùng tự động hoàn thành SDK Địa điểm dành cho iOS
  • Ngay từ đầu, hãy tìm hiểu về các trường dữ liệu cần thiết của tính năng Tự động điền địa điểm.
  • Các trường thiên vị vị trí và hạn chế vị trí là không bắt buộc nhưng có thể ảnh hưởng đáng kể đến hiệu suất của tính năng tự động hoàn thành.
  • Sử dụng tính năng xử lý lỗi để đảm bảo ứng dụng của bạn giảm hiệu suất một cách linh hoạt nếu API trả về lỗi.
  • Đảm bảo ứng dụng của bạn xử lý khi không có lựa chọn nào và cung cấp cho người dùng một cách để tiếp tục.

Các phương pháp hay nhất để tối ưu hoá chi phí

Tối ưu hoá chi phí cơ bản

Để tối ưu hoá chi phí sử dụng dịch vụ Tự động điền địa điểm, hãy sử dụng mặt nạ trường trong tiện ích Chi tiết địa điểm và Tự động điền địa điểm để chỉ trả về các trường dữ liệu địa điểm mà bạn cần.

Tối ưu hoá chi phí nâng cao

Hãy cân nhắc việc triển khai tính năng Tự động hoàn thành địa điểm theo phương thức lập trình để truy cập vào Giá theo yêu cầu và yêu cầu Kết quả của API Địa chỉ về địa điểm đã chọn thay vì Thông tin chi tiết về địa điểm. Giá theo yêu cầu kết hợp với API Địa chỉ được mã hoá địa lý sẽ tiết kiệm chi phí hơn so với giá theo phiên (dựa trên phiên) nếu đáp ứng cả hai điều kiện sau:

  • Nếu bạn chỉ cần vĩ độ/kinh độ hoặc địa chỉ của địa điểm mà người dùng đã chọn, thì API Địa chỉ được mã hoá địa lý sẽ cung cấp thông tin này với chi phí thấp hơn một lệnh gọi Thông tin chi tiết về địa điểm.
  • Nếu người dùng chọn một cụm từ gợi ý tự động hoàn thành trong trung bình 4 yêu cầu cụm từ gợi ý tự động hoàn thành trở xuống, thì mức giá Theo yêu cầu có thể tiết kiệm chi phí hơn so với mức giá Theo phiên.
Để được trợ giúp về cách chọn cách triển khai tính năng Tự động hoàn thành địa điểm phù hợp với nhu cầu của bạn, hãy chọn thẻ tương ứng với câu trả lời của bạn cho câu hỏi sau.

Ứng dụng của bạn có yêu cầu thông tin nào khác ngoài địa chỉ và vĩ độ/kinh độ của thông tin dự đoán đã chọn không?

Có, cần thêm thông tin

Sử dụng tính năng Tự động hoàn thành địa điểm dựa trên phiên với Thông tin chi tiết về địa điểm.
Vì ứng dụng của bạn yêu cầu Thông tin chi tiết về địa điểm, chẳng hạn như tên địa điểm, trạng thái hoạt động kinh doanh hoặc giờ mở cửa, nên khi triển khai tính năng Tự động hoàn thành địa điểm, bạn phải sử dụng mã thông báo phiên (theo phương thức lập trình hoặc được tích hợp vào tiện ích JavaScript, Android hoặc iOS) với tổng chi phí là 0,017 USD cho mỗi phiên cộng với SKU Dữ liệu địa điểm hiện hành tuỳ thuộc vào trường dữ liệu địa điểm mà bạn yêu cầu.1

Triển khai tiện ích
Tính năng quản lý phiên được tự động tích hợp vào tiện ích JavaScript, Android hoặc iOS. Trong đó bao gồm cả yêu cầu Tự động hoàn thành địa điểm và yêu cầu Chi tiết địa điểm trên cụm từ gợi ý đã chọn. Hãy nhớ chỉ định tham số fields để đảm bảo bạn chỉ yêu cầu các trường dữ liệu về địa điểm mà bạn cần.

Triển khai có lập trình
Sử dụng mã thông báo phiên với các yêu cầu Tự động hoàn thành địa điểm. Khi yêu cầu Thông tin chi tiết về địa điểm về thông tin dự đoán đã chọn, hãy thêm các tham số sau:

  1. Mã địa điểm trong phản hồi của tính năng Tự động hoàn thành địa điểm
  2. Mã thông báo phiên được dùng trong yêu cầu Tự động hoàn thành địa điểm
  3. Tham số fields chỉ định các trường dữ liệu vị trí mà bạn cần

Không, chỉ cần địa chỉ và vị trí

API Địa chỉ được mã hoá địa lý có thể là một lựa chọn tiết kiệm chi phí hơn so với Chi tiết địa điểm cho ứng dụng của bạn, tuỳ thuộc vào hiệu suất của tính năng Tự động hoàn thành địa điểm. Hiệu suất của tính năng Tự động hoàn thành của mỗi ứng dụng sẽ khác nhau tuỳ thuộc vào nội dung người dùng đang nhập, vị trí ứng dụng đang được sử dụng và việc bạn đã triển khai các phương pháp hay nhất để tối ưu hoá hiệu suất hay chưa.

Để trả lời câu hỏi sau, hãy phân tích số lượng ký tự trung bình mà người dùng nhập trước khi chọn một nội dung dự đoán Tự động hoàn thành địa điểm trong ứng dụng của bạn.

Trung bình, người dùng có chọn một cụm từ gợi ý tự động hoàn thành về Địa điểm trong 4 yêu cầu trở xuống không?

Triển khai tính năng Tự động hoàn thành địa điểm theo phương thức lập trình mà không cần mã thông báo phiên và gọi API Địa chỉ (Geocoding API) trên thông tin gợi ý về địa điểm đã chọn.
API Mã hoá địa lý cung cấp địa chỉ và toạ độ vĩ độ/kinh độ với mức phí 0,005 USD/yêu cầu. Việc tạo 4 yêu cầu Tự động hoàn thành địa điểm – Mỗi yêu cầu sẽ tốn 0,01132 đô la. Vì vậy, tổng chi phí của 4 yêu cầu cộng với một lệnh gọi Geocoding API về thông tin gợi ý địa điểm đã chọn sẽ là 0,01632 đô la, thấp hơn giá của tính năng Tự động hoàn thành theo phiên là 0,017 đô la/phiên.1

Hãy cân nhắc việc áp dụng các phương pháp hay nhất về hiệu suất để giúp người dùng nhận được nội dung gợi ý mà họ đang tìm kiếm chỉ bằng một vài ký tự.

Không

Sử dụng tính năng Tự động hoàn thành địa điểm dựa trên phiên với Thông tin chi tiết về địa điểm.
Vì số lượng yêu cầu trung bình mà bạn dự kiến sẽ thực hiện trước khi người dùng chọn một kết quả dự đoán của tính năng Tự động hoàn thành địa điểm vượt quá chi phí theo mô hình tính phí theo Phiên, nên khi triển khai tính năng Tự động hoàn thành địa điểm, bạn phải sử dụng mã thông báo phiên cho cả yêu cầu Tự động hoàn thành địa điểm và yêu cầu Thông tin chi tiết về địa điểm được liên kết với tổng chi phí là 0,017 USD cho mỗi phiên.1

Triển khai tiện ích
Tính năng quản lý phiên được tự động tích hợp vào tiện ích JavaScript, Android hoặc iOS. Trong đó bao gồm cả yêu cầu Tự động hoàn thành địa điểm và yêu cầu Chi tiết địa điểm trên cụm từ gợi ý đã chọn. Hãy nhớ chỉ định tham số fields để đảm bảo bạn chỉ yêu cầu các trường Dữ liệu cơ bản.

Triển khai có lập trình
Sử dụng mã thông báo phiên với các yêu cầu Tự động hoàn thành địa điểm. Khi yêu cầu Thông tin chi tiết về địa điểm về thông tin dự đoán đã chọn, hãy thêm các tham số sau:

  1. Mã địa điểm trong phản hồi của tính năng Tự động hoàn thành địa điểm
  2. Mã thông báo phiên được dùng trong yêu cầu Tự động hoàn thành địa điểm
  3. Tham số fields chỉ định các trường Dữ liệu cơ bản như địa chỉ và hình học

Cân nhắc trì hoãn các yêu cầu Tự động điền địa điểm
Bạn có thể áp dụng các chiến lược như trì hoãn yêu cầu Tự động điền địa điểm cho đến khi người dùng nhập ba hoặc bốn ký tự đầu tiên để ứng dụng của bạn gửi ít yêu cầu hơn. Ví dụ: việc tạo các yêu cầu Tự động hoàn thành địa điểm cho mỗi ký tự sau khi người dùng nhập ký tự thứ ba có nghĩa là nếu người dùng nhập 7 ký tự rồi chọn một cụm từ gợi ý mà bạn tạo một yêu cầu API Mã hoá địa lý, thì tổng chi phí sẽ là 0,01632 đô la Mỹ (4 * 0,00283 đô la Mỹ cho mỗi yêu cầu Tự động hoàn thành + 0,005 đô la Mỹ cho mỗi yêu cầu Mã hoá địa lý).1

Nếu việc trì hoãn yêu cầu có thể làm giảm số yêu cầu có lập trình trung bình xuống dưới 4, thì bạn có thể làm theo hướng dẫn để triển khai tính năng Tự động hoàn thành địa điểm hiệu quả bằng API Địa chỉ mã hoá địa lý. Xin lưu ý rằng người dùng có thể coi việc trì hoãn các yêu cầu là độ trễ, vì họ có thể mong đợi thấy nội dung dự đoán với mỗi thao tác nhấn phím mới.

Hãy cân nhắc việc áp dụng các phương pháp hay nhất về hiệu suất để giúp người dùng nhận được nội dung gợi ý mà họ đang tìm kiếm trong ít ký tự hơn.


  1. Chi phí được liệt kê ở đây tính theo USD. Vui lòng tham khảo trang Thanh toán trên Google Maps Platform để biết toàn bộ thông tin về giá.

Các phương pháp hay nhất về hiệu suất

Các nguyên tắc sau đây mô tả cách tối ưu hoá hiệu suất của tính năng Tự động hoàn thành địa điểm:

  • Thêm các quy định hạn chế về quốc gia, tính năng thiên vị vị trí và lựa chọn ưu tiên về ngôn ngữ (đối với việc triển khai theo phương thức lập trình) vào quá trình triển khai tính năng Tự động hoàn thành địa điểm. Bạn không cần lựa chọn ưu tiên về ngôn ngữ cho tiện ích vì các tiện ích sẽ chọn lựa chọn ưu tiên về ngôn ngữ từ trình duyệt hoặc thiết bị di động của người dùng.
  • Nếu tính năng Tự động hoàn thành địa điểm đi kèm với bản đồ, bạn có thể thiên vị vị trí theo khung nhìn bản đồ.
  • Trong trường hợp người dùng không chọn một trong các cụm từ gợi ý của tính năng Tự động hoàn thành, thường là vì không có cụm từ gợi ý nào là địa chỉ kết quả mong muốn, bạn có thể sử dụng lại dữ liệu đầu vào ban đầu của người dùng để cố gắng nhận được kết quả phù hợp hơn:
    • Nếu bạn muốn người dùng chỉ nhập thông tin địa chỉ, hãy sử dụng lại dữ liệu đầu vào ban đầu của người dùng trong lệnh gọi đến API Mã hoá địa lý.
    • Nếu bạn muốn người dùng nhập cụm từ tìm kiếm cho một địa điểm cụ thể theo tên hoặc địa chỉ, hãy sử dụng yêu cầu Tìm địa điểm. Nếu bạn chỉ mong đợi kết quả ở một khu vực cụ thể, hãy sử dụng tính năng thiên vị vị trí.
    Sau đây là một số trường hợp khác mà bạn nên quay lại sử dụng API Địa chỉ được mã hoá địa lý:
    • Người dùng nhập địa chỉ cơ sở phụ ở những quốc gia chưa hỗ trợ đầy đủ tính năng Tự động hoàn thành địa điểm cho địa chỉ cơ sở phụ, ví dụ: Cộng hoà Séc, Estonia và Lithuania. Ví dụ: địa chỉ bằng tiếng Séc "Stroupežnického 3191/17, Praha" sẽ cho ra một phần nội dung gợi ý trong tính năng Tự động hoàn thành địa điểm.
    • Người dùng nhập địa chỉ có tiền tố đoạn đường như "23-30 29th St, Queens" ở Thành phố New York hoặc "47-380 Kamehameha Hwy, Kaneohe" trên đảo Kauai ở Hawaii.

Khắc phục sự cố

Mặc dù có thể xảy ra nhiều lỗi, nhưng phần lớn lỗi mà ứng dụng của bạn có thể gặp phải thường là do lỗi cấu hình (ví dụ: sử dụng sai khoá API hoặc định cấu hình sai khoá API) hoặc lỗi hạn mức (ứng dụng của bạn đã vượt quá hạn mức). Hãy xem phần Hạn mức sử dụng để biết thêm thông tin về hạn mức.

Các lỗi xảy ra trong quá trình sử dụng các chế độ kiểm soát tự động hoàn thành sẽ được trả về trong phương thức didFailAutocompleteWithError() của nhiều giao thức uỷ quyền. Thuộc tính code của đối tượng NSError được cung cấp được đặt thành một trong các giá trị của enum GMSPlacesErrorCode.