Google 地图 API for Android

原文:Introduction to Google Maps API for Android
作者: Eunice Obugyei
译者:kmyhy

从健康类 app Runkeeper 到游戏 app 精灵宝可梦,位置服务对现代 app 来说越来越重要。

在本文中,我们将创建一个 app。名字就叫做 City Guide。

这个 app 同意用户搜索一个地点,使用 Google 地图显示这个地点的位置并监听用户的位置改变。

我们将学习怎样使用 Google 地图 API for Android,Google 的位置服务 API 和 Google 的 Places API for Android 完毕例如以下工作:

  • 显示用户当前位置
  • 在地图上显示和自己定义大头钉
  • 查询给定坐标的位置信息
  • 监听位置变化
  • 搜索兴趣点

注意:本 Google 地图 API 教程假设你熟悉主要的 Android 开发。假设你第一次接触 Android 开发,请阅读我们的 Android 新手教程 来学习基础知识。

開始

打开 Android Studio,在高速启动菜单中选择 Start a new Android Studio project:

在创建新项目对话框,New Project 视图,输入 app 名称 City Guide,选择保存地址。点击 Next。

在 Target Android Devices 窗体,勾选 Phone and Tablet 选框。选择你想要 app 支持的 minimum SDK。从 Minimum SDK 的下拉框中选择 API 14。然后点 Next。

在 Add an Activity to Mobile 窗体。选择 Google Maps Activity 然后点 Next。

在 Customize the Activity 窗体。点击 Finish,完毕项目的创建。

Android Studio 将启动 Gradle 并编译项目。这会花几分钟。
打开 MapsActivity.java。它应该是这个样子:

package com.raywenderlich.cityguide;

import android.support.v4.app.FragmentActivity;
import android.os.Bundle;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;

// 1
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {

  private GoogleMap mMap;

  // 2
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_maps);
    // Obtain the SupportMapFragment and get notified when the map is ready to be used.
    SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
        .findFragmentById(R.id.map);
    mapFragment.getMapAsync(this);
  }

  // 3
  @Override
  public void onMapReady(GoogleMap googleMap) {
    mMap = googleMap;

    // Add a marker in Sydney and move the camera
    LatLng sydney = new LatLng(-34, 151);
    mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney"));
    mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));
  }
}
  1. MapsActivity 实现了 OnMapReadyCallback 接口并继承了 FragmentActivity。
  2. 这个类覆盖了 FragmentActivity 的 onCreate() 方法。
  3. 同一时候覆盖了 OnMapReadyCallback 的 onMapReady() 方法。

    这种方法在地图准备就绪时调用。在这种方法中,创建了一个 marker(大头钉),坐标位于澳大利亚悉尼,然后将 marker 方到地图上。

Android Studio 在 manifests/AndroidManifest.xml 中加入了例如以下代码:

  1. 一个 ACCESS_FINE_LOCATION 权限声明。要訪问用户的精确位置,这不可缺少。
  2. 加入了一个 com.google.android.geo.API_KEY 的 meta-data。这保存了 API key。

Android Studio 也在 build.gradle 中加入了一个 Google Play Service 的依赖。

这个依赖将 Google 地图和定位服务 API 暴露给 app 使用。

compile 'com.google.android.gms:play-services:VERSION_HERE'

当编译完毕后,执行 app 你会看到:

你看到一个空白窗体,上面没有地图。你还没有为 Google Map 创建 API key。

我们将在下一节创建。

注意:假设你使用模拟器,模拟器所安装的版本号必须满足 build.gradle 文件里 Google Play Service 所要求的版本号。

假设你看到提示须要升级模拟器的 Google Play Service 版本号,你能够从 Android Studio SDK 管理器中下载最新的 Google APIs 并安装到虚拟设备,或者减少 gradle 依赖中的版本号。

使用 Google 地图 APIs

要使用不论什么 Google 地图 API,都须要创建一个 API key 并从开发人员控制台中启用所需的 API。

假设你没有 Google 账号,如今就去创建它——免费的!

创建 API Key

打开 res/values/google_maps_api.xml,你会看到:

如今复制粘贴上图中的链接到浏览器中。


在 Enable an API 页。选择 Create a project 然后点 Continue。

在下一页,点 Create API key button。

然后,复制 API key created 对话框中的 API key。点击 Close。

回到 google_maps_api.xml, 将 google_maps_key 替换成刚才拷贝的 API key。
执行 app,你会看到地图和地图上的红色大头钉。

回到 developer console,打开 Google Places API for Android。我们会在后面用这个 API 查找 Place。

建立 Play Services 连接

在编写 Java 代码之前,我们须要配置一下 Android Studio 让它自己主动为我们插入 import 语句,节省我们的工作量。


依次打开 Android Studio > Preferences > Editor > General > Auto Import 菜单,选择 Add unambiguous imports on the fly 和 Show import popup 选项,点击 OK。

打开 MapsActivity.java ,让 MapsActivity 实现下列接口:

public class MapsActivity extends FragmentActivity implements OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, GoogleMap.OnMarkerClickListener, LocationListener

import LocationListener 一句产生了歧义,因此告诉 Android Studio 去 Google Mobile Services 进行导入:

import com.google.android.gms.location.LocationListener;

上述代码解释例如以下:

  • GoogleApiClient.ConnectionCallbacks 提供了一个回调,当client和server成功建立连接时调用(onConnected()) 或者暂时性的断开时调用 (onConnectionSuspended())。
  • GoogleApiClient.OnConnectionFailedListener 提供了一个回调方法 (onConnectionFailed()) 。当client连接server失败时调用。
  • GoogleMap.OnMarkerClickListener 定义了一个 onMarkerClick() 方法,当大头钉被点击时调用。
  • LocationListener 定义了 onLocationChanged() 方法,当用户位置改变时调用。这种方法唯独 LocationListener 注冊以后才会调用。

如今。实现上述接口定义的方法。要这样做,能够按以下步骤:

  1. 把光标放在类声明的随意地方,点击类声明上显示的红色灯泡。

  2. 选择 Implement methods。

  3. 在 Select Methods to implement 对话框。点击 OK。

这些方法的实现会加入到类中。

要连接 Google Play Services 库中的 Google API,你须要先创建一个 GoogleApiClient。

在 MapsActivity.java 中加入一个字段:

private GoogleApiClient mGoogleApiClient;

在 onCreate() 中加入:

// 1
if (mGoogleApiClient == null) {
  mGoogleApiClient = new GoogleApiClient.Builder(this)
      .addConnectionCallbacks(this)
      .addOnConnectionFailedListener(this)
      .addApi(LocationServices.API)
      .build();
}

加入两个方法:

@Override
protected void onStart() {
  super.onStart();
  // 2
  mGoogleApiClient.connect();
}

@Override
protected void onStop() {
  super.onStop();
  // 3
  if( mGoogleApiClient != null && mGoogleApiClient.isConnected() ) {
    mGoogleApiClient.disconnect();
  }
}

代码说明:

  1. 假设 mGoogleApiClient 变量为空。进行初始化。
  2. 打开一个后台连接。连接到 Google Play 服务。
  3. 假设客服端不为空且状态为已连接的话,关闭连接。

加入下列代码到 onMapReady():

mMap.getUiSettings().setZoomControlsEnabled(true); 
mMap.setOnMarkerClickListener(this);

这里我们开启了地图的缩放控制并指定了 MapsActdivity 作为回调,这样当用户点击大头钉时能够进行处理。

如今。点击地图上位于悉尼的大头钉。你会看到显示了标题文本:

输入另外一个坐标,大头钉会移到你指定的位置。

加入下列代码将大头钉设置到纽约,标题文本设置“My Favorite City”:

LatLng myPlace = new LatLng(40.73, -73.99);  // this is New York 
mMap.addMarker(new MarkerOptions().position(myPlace).title("My Favorite City"));
mMap.moveCamera(CameraUpdateFactory.newLatLng(myPlace));

编译执行。

注意。地图自己主动将中心和大头钉对齐,moveCamera() 的作用就在于次。可是。地图的缩放比例不对,由于它是缩得太小了。

将 moveCamera() 方法调用改动为:

mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(myPlace, 12));

缩方比例 0 表示将地图缩小为最小的世界地图。

大部分地图都支持缩放比例到 20,更远的地区只支持到 13。将它设为二者之间的 12 比較合适,显示较多的细节且不会太近。

执行 app 以查看效果。

用户权限

我们的 app 须要使用 ACCESS_FINE_LOCATION 权限以获得用户定位信息。在 AndroidManifest.xml 中我们已经进行了声明。

从 Android 6.0 開始。用户权限与之前发生了一点点差别。

你不会在安装 app 时请求权限,而是在执行时。当权限真正须要用到时才请求。

权限分为两种类别:普通权限和危急权限。

对于危急权限须要在执行时向用户请求授权。

要求訪问用户隐私的权限比方訪问用户通讯录、日历、定位等就属于危急权限。

打开 MapsActivity.java 加入下列变量:

private static final int LOCATION_PERMISSION_REQUEST_CODE = 1;

新加一个方法 setUpMap() 。

private void setUpMap() {
  if (ActivityCompat.checkSelfPermission(this,
    android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this, new String[]
      {android.Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_PERMISSION_REQUEST_CODE);  
    return;
  }
}

上述代码推断 app 是否获得了 ACCESS_FINE_LOCATION 权限。

假设没有,向用户请求授权。

然后在 onConnectded() 方法中调用这种方法:

@Override
public void onConnected(@Nullable Bundle bundle) {
  setUpMap();
}

编译执行。当请求授权时点击 Allow。

注意:关于用户权限的完整介绍超出了本文的范畴。请參考执行时请求授权的文档

获取当前坐标

定位服务的最常见任务是获得用户当前坐标。我们通过 Google Play 服务定位 API 请求用户设备的最新坐标来实现这个目的。

在 MapsActivity.java, 加入变量:

private Location mLastLocation;

然后,在setUpMap() 最后一句加入代码:

// 1
mMap.setMyLocationEnabled(true);

// 2
LocationAvailability locationAvailability =
    LocationServices.FusedLocationApi.getLocationAvailability(mGoogleApiClient);
if (null != locationAvailability && locationAvailability.isLocationAvailable()) {
  // 3
  mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
  // 4
  if (mLastLocation != null) { 
    LatLng currentLocation = new LatLng(mLastLocation.getLatitude(), mLastLocation
        .getLongitude());
    mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(currentLocation, 12));
  }
}

代码说明:

  1. setMyLocationEnabled 一句打开了 my-location 图层。用于在用户坐标出绘制一个浅蓝色的圆点。同一时候加一个button到地图上,当你点击它。地图中心会移动到用户的坐标。
  2. getLocationAvailability 一句推断设备上的位置信息是否有效。
  3. getLastLocation 一句同意你获得当前有效的最新坐标。

  4. 假设能够获得最新坐标,将镜头对准用户当前坐标。

编译执行,查看效果。你会看到在用户当前坐标有一个浅蓝色的圆点:

在模拟器上进行測试

要測试地图类 app,最好用真正的 Android 设备。假设由于某种原因不得不在模拟器上測试,你能够用模拟器模拟出坐标数据。

要做到这个。一种办法是使用模拟器的扩展控制(extended controls)。你须要这样做:

  1. 打开模拟器。

    在右边面板中,点击 More button(…) 以訪问 extended controls。

  2. 在 Extended Controls 对话框的左边,选择 Location。
  3. 在下图指定位置输入经纬度。点击 Send。

大头钉

注意最后一次执行 app 时。用户位置所在的蓝点非常显眼。Android 地图 API 同意你使用大头钉,这是一种图标,用于放在地图上层的指定位置。

在 MapsActivity.java 中加入代码:

protected void placeMarkerOnMap(LatLng location) {
  // 1
  MarkerOptions markerOptions = new MarkerOptions().position(location);
  // 2
  mMap.addMarker(markerOptions);
}
  1. 创建了一个 MarkerOptions 对象并将大头钉要放在的位置设置为用户当前坐标。

  2. 将大头钉加入到地图。

将 setUpMap() 方法替换为:

private void setUpMap() {
  if (ActivityCompat.checkSelfPermission(this,
      android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this, new String[]
        {android.Manifest.permission.ACCESS_FINE_LOCATION},LOCATION_PERMISSION_REQUEST_CODE);
    return;
  }

  mMap.setMyLocationEnabled(true);

  LocationAvailability locationAvailability =
      LocationServices.FusedLocationApi.getLocationAvailability(mGoogleApiClient);
  if (null != locationAvailability && locationAvailability.isLocationAvailable()) {
    mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
    if (mLastLocation != null) {
      LatLng currentLocation = new LatLng(mLastLocation.getLatitude(), mLastLocation
          .getLongitude());
      //add pin at user's location
      placeMarkerOnMap(currentLocation);
      mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(currentLocation, 12));
    }
  }
}

setUpMap() 方法中的改变不过调用了 placeMarkerOnMap() 以显示大头钉。


编译执行查看效果。你如今会在用户位置看到一个大头钉:

假设你不喜欢 Android 默认的大头钉样式,你也能够创建自己的图片代替。

回到 placeMarkerOnMap() 方法。在 MarkerOptions 初始化之后加入下句:

markerOptions.icon(BitmapDescriptorFactory.fromBitmap(BitmapFactory.decodeResource
    (getResources(), R.mipmap.ic_user_location)));

这里下载自己定义大头钉文件 ic_user_location,然后解压缩。

将全部文件复制到 mipmap 文件夹:

编译执行查看效果。在你当前位置的大头钉如今使用了项目中的 ic_user_location 图片:

假设不过改动默认大头钉的颜色呢?请自行进行尝试,假设有难度请參考这个答案:

在 placeMarkerOnMap() 中使用这句:

```java

markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN));
“`
这会将默认大头钉的红色换成绿色。

![](https://koenig-media.raywenderlich.com/uploads/2016/10/Screen-Shot-2016-10-02-at-10.57.55-PM.png)

改变地图类型

依据 app 要实现的功能,一般的地图视图可能对你就不够用了。

Android 地图 API 提供了几种地图类型:MAP_TYPE_NORMAL、MAP_TYPE_SATELLITE、 MAP_TYPE_TERRAIN、MAP_TYPE_HYBRID。


在 setUpMain() 方法的 setMyLocationEnabled() 后面加入一句:

mMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN);

GoogleMap.MAP_TYPE_TERRAIN 显示更具体的地形。显示地貌变化:

视图 a more detailed view of the area, showing changes in elevation:

其它类型的效果:

GoogleMap.MAP_TYPE_SATELLITE 显示卫星地图,没有文字标注。

GoogleMap.MAP_TYPE_HYBRID 显示卫星地图和普通视图的结合。

GoogleMap.MAP_TYPE_NORMAL 显示典型的街道地图并标注标签。这也是默认的类型。

实现地理编码

如今你已经获得了用户的坐标,假设在用户点击大头钉时显示地理名称就好了。Google 有一个 Geocoder 就是用来干这个的。

它将经纬度坐标转换为一个人类可读的地址,或者与此相反。

打开 MapsActivity,加入方法:

private String getAddress( LatLng latLng ) {
  // 1
  Geocoder geocoder = new Geocoder( this );
  String addressText = "";
  List<Address> addresses = null;
  Address address = null;
  try {
    // 2
    addresses = geocoder.getFromLocation( latLng.latitude, latLng.longitude, 1 );
    // 3
    if (null != addresses && !addresses.isEmpty()) {
      address = addresses.get(0);
      for (int i = 0; i < address.getMaxAddressLineIndex(); i++) {
        addressText += (i == 0)?

address.getAddressLine(i):(" " + address.getAddressLine(i)); } } } catch (IOException e ) { } return addressText; }

关键在于 Address 类是有歧义的。要解决问题。须要将 import 语句指定为:

import android.location.Address;

代码说明:

  1. 创建一个 Geocoder 对象,用于将一个经纬度坐标转换成地址或进行相反的转换。
  2. 使用 geocoder 将方法參数接收到的经纬度转换成地址信息。
  3. 假设响应的 addresses 中包括有地址信息,将这些信息拼接为一个字符串返回。

将 placeMarkerOnMap() 方法改动为:

protected  void placeMarkerOnMap(LatLng location) {
  MarkerOptions markerOptions = new MarkerOptions().position(location);

  String titleStr = getAddress(location);  // add these two lines
  markerOptions.title(titleStr);

  mMap.addMarker(markerOptions);
}

在这种方法中加入了一句 getAddress() 调用,并将地址设置为大头钉标题。

编译执行以查看效果。点击大头钉,你会看到地址:

点击地图的其它地方。地址消失。
注意。假设你走动位置。蓝点会跟着你一起移动,但大头钉不会。假设你在真机上測试,试着四处移动一下位置。假设在模拟器上測试,将你的坐标用 emulator control 改动到别的地方。

大头钉不会移动是由于我们的代码还不知道什么时候位置发生了变化。

小蓝点位置由 Google API 自己管理,而不是我们的代码做的。假设想让 marker 尾随小蓝点移动,须要在代码中接收位置变化通知。

接收位置变化

随时知道用户的位置有助于提供一种良好体验。本节将介绍怎样实时接收用户位置的变化。
为了做到这一点,你须要创建一个 location request。
打开 MapsActivity。添加变量:

// 1
private LocationRequest mLocationRequest;
private boolean mLocationUpdateState;
// 2
private static final int REQUEST_CHECK_SETTINGS = 2;
  1. 声明一个 LocationRequest 变量以及一个保存位置更新状态的变量。
  2. REQUEST_CHECK_SETTINGS 是用于传递给 onActivityResult 方法的 request code。
    然后加入方法:
protected void startLocationUpdates() {
  //1
  if (ActivityCompat.checkSelfPermission(this,
      android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){
    ActivityCompat.requestPermissions(this,
               new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
               LOCATION_PERMISSION_REQUEST_CODE);  
    return;
  }
  //2
  LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest,
  this);
}
  1. startLocationUpdates() 中,假设 ACCESS_FINE_LOCATION 权限未获取。则请求授权并返回。

  2. 假设已经获得授权。请求位置变化信息。

然后加入方法:

// 1
protected void createLocationRequest() {
  mLocationRequest = new LocationRequest();
  // 2
  mLocationRequest.setInterval(10000); 
  // 3
  mLocationRequest.setFastestInterval(5000); 
  mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

  LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
      .addLocationRequest(mLocationRequest);

  PendingResult<LocationSettingsResult> result =
      LocationServices.SettingsApi.checkLocationSettings(mGoogleApiClient,
          builder.build());

  result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
    @Override
    public void onResult(@NonNull LocationSettingsResult result) {
      final Status status = result.getStatus();
      switch (status.getStatusCode()) {
        // 4
        case LocationSettingsStatusCodes.SUCCESS: 
          mLocationUpdateState = true;
          startLocationUpdates();
          break;
        // 5
        case LocationSettingsStatusCodes.RESOLUTION_REQUIRED: 
          try {
            status.startResolutionForResult(MapsActivity.this, REQUEST_CHECK_SETTINGS);
          } catch (IntentSender.SendIntentException e) {
          }
          break;
        // 6
        case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE: 
          break;
      }
    }
  });
}

ResultCallback 类的 import 语句有歧义,因此加入下列 import 语句:

import com.google.android.gms.common.api.ResultCallback;

createLocationRequest() 方法代码说明例如以下:

  1. 创建一个 LocationRequest 对象,将它加入到一个 LocationSettingsRequest.Builder 对象,并基于用户位置设置的当前状态查询位置变化信息并处理。
  2. setInterval() 指定了 app 多长时间接受一次变化通知。

  3. setFastestInterval() 指定 app 能够处理的变化通知的最高速度。设置fastestInterval 能够限制位置变化通知发送给你的 app 的频率。

    在開始请求位置变化通知之前。须要检查用户位置设置的状态。

  4. SUCCESS 状态说明一切正常。你能够初始化一个 location request。
  5. RESOLUTION_REQUIRED 状态表明位置设置有一个问题有待修复。有可能是由于用户的位置设置被关闭了。你能够向用户显示一个对话框:

  6. SETTINGS_CHANGE_UNAVAILABLE 状态表明位置设置有一些无法修复的问题。

    有可能是用户在上面的对话框里选择了 NEVER。

如今加入下列方法:

// 1
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  super.onActivityResult(requestCode, resultCode, data);
  if (requestCode == REQUEST_CHECK_SETTINGS) {
    if (resultCode == RESULT_OK) {
      mLocationUpdateState = true;
      startLocationUpdates();
    }
  }
}

// 2
@Override
protected void onPause() {
  super.onPause();
  LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}

// 3
@Override
public void onResume() {
  super.onResume();
  if (mGoogleApiClient.isConnected() && !mLocationUpdateState) {
    startLocationUpdates();
  }
}

代码说明:

  1. 覆盖 FragmentActivity 的 onActivityResult() 方法。假设REQUEST_CHECK_SETTINGS 请求返回的是一个 RESULT_OK,则发起位置更新请求。

  2. 覆盖 onPause() 方法。停止位置变化请求。

  3. 覆盖 onResume() 方法。又一次開始位置更新请求。

然后,在 onCreate() 方法的最后调用 createLocationRequest() 方法。

createLocationRequest();

然后,在 onConnected() 方法中加入例如以下语句:

if (mLocationUpdateState) {
  startLocationUpdates();
}

假设用户的位置设置是打开状态的话,启动位置更新。

在 onLocationChanged() 方法中加入:

mLastLocation = location;
if (null != mLastLocation) {
  placeMarkerOnMap(new LatLng(mLastLocation.getLatitude(), mLastLocation.getLongitude()));
}

这里。我们改动 mLastLocation 为最新的位置并用新位置坐标刷新地图显示。

你的 app 如今已经能够接受位置变化通知了。当你改变位置,地图上的大头钉会随位置的改变而变。

注意。点击大头钉仍然能够看到地址信息。
编译执行。四处走动查看变化:

查询兴趣点

由于 app 是用于扮演一个向导的角色,用户应该能够找到他们感兴趣的地方吧?

这就是 Google Places API 出场的时候了。它让你的 app 能够搜索数百万计的兴趣点和大型机构。Android 库有很多非常酷的功能,当中之中的一个就是 Place Picker,这是一个 UI widget。同意你用寥寥数行代码就实现一个搜索 PIO(兴趣点)的功能。太好了,这是真的吗?你能够试一试。

打开MapsActivity,加入变量:

private static final int PLACE_PICKER_REQUEST = 3;

然后加入下列方法:


private void loadPlacePicker() {
  PlacePicker.IntentBuilder builder = new PlacePicker.IntentBuilder();

  try {
    startActivityForResult(builder.build(MapsActivity.this), PLACE_PICKER_REQUEST);
  } catch(GooglePlayServicesRepairableException | GooglePlayServicesNotAvailableException e) {
      e.printStackTrace();
  }
}

这种方法创建了新的 builder 用于创建 intent,这个 Intent 用于打开一个 Place Picker UI,然后打开这个 PlacePicker Intent。

将下列语句加入到 onActivityResult():

if (requestCode == PLACE_PICKER_REQUEST) {
  if (resultCode == RESULT_OK) {
    Place place = PlacePicker.getPlace(this, data);
    String addressText = place.getName().toString();
    addressText += "
" + place.getAddress().toString();

    placeMarkerOnMap(place.getLatLng());
  }
}

在这里,假设请求代码是 PLACE_PICKER_REQUEST 且返回码是 RESULT_OK。则读取所选地点的信息。然后放一个大头钉在该位置。

搜索 PIO 基本搞定——剩下的就是调用 loadPlacePicker() 方法。

我们须要创建一个浮动的 Action button(FAB)在地图右下角并用于调用这种方法。FAB 须要使用 CoordinatorLayout。这是 design 支持库中的内容。

首先,打开 build.gradle 加入依赖 Android support design library:

dependencies {
  ...
  compile 'com.android.support:design:24.1.1'
}

注意:通常,假设你用的 Android SDK 版本号比較新,你可能须要同一时候升级这个依赖的的版本号,以便二者匹配。

然后改动 res > layout > activity_maps.xml 为:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <fragment
        android:id="@+id/map"
        class="com.google.android.gms.maps.SupportMapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:src="@android:drawable/ic_menu_search"/>

</android.support.design.widget.CoordinatorLayout>

我们在原先的地图上已经有一个用于显示地图的 fragment。如今所做的就是加入一个 FAB。

在 MapsActivity 的 onCreate() 方法,加入例如以下代码:


FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View view) {
    loadPlacePicker();
  }
});

编译执行。点击地图下方的 search button。会弹出 place picker:

https://koenig-media.raywenderlich.com/uploads/2016/09/placepickerdemo4.gif” width= “320”/>

结束

这里下载终于完毕的项目。


关于 Google 地图 APIs,本文只介绍了非常少一部分。在 Google 官方文档中。有很多其它关于 web service 和这个 Android API 的内容。

你还能够查看开发人员页面中其它定制大头钉的方法。本文中的执行时用户权限检查须要改进,这里也有非常好的东西能够參考:关于更高级的权限授权

很多其它阅读,请參考开发人员页面:Google Places API for Android接受位置变化通知 和模拟位置数据模拟器的 extendet controls

有问题和建议,请在以下留言。

原文地址:https://www.cnblogs.com/mthoutai/p/7290734.html