カメラとビュー

チルトも回転も簡単な操作で行える Maps SDK for Android のマップでは、ユーザーは見たい向きにマップを調整できます。ベクターベースのマップタイルはフットプリントが小さく、どのズームレベルでマップをパンしても視点を変更しても、遅延はほとんど生じません。

コードサンプル

GitHub の ApiDemos リポジトリには、カメラの機能を示すサンプルが含まれています。

はじめに

ウェブの Google マップと同様に、Maps SDK for Android では、メルカトル図法を使ってデバイスの画面(平面)上に世界の表面(球面)を表します。世界は継ぎ目なく球面を包むように存在しているため、東と西の方向には、マップが無限に繰り返されます。北と南の方向では、マップが約 85 度北と 85 度南までに制限されています。

注: メルカトル図法では、経度を表す幅は有限ですが、緯度を表す高さは無限です。そこで、最終的なマップ形状が正方形になるように、メルカトル図法を利用して約 +/- 85 度で基本地図の画像を切り取っています。これにより、タイル選択が簡単になります。

Maps SDK for Android では、マップのカメラを変更することで、ユーザーの視点位置を変更できます。

カメラに変更を加えても、追加したマーカーやオーバーレイなどのグラフィックは変更されませんが、新しいビューでより適切に表示されるようにこれらを変更するほうがよい場合があります。

マップでのユーザー操作をリッスンすることができるため、ユーザーの要求に応じてマップを変更できます。たとえば、コールバック メソッド OnMapClickListener.onMapClick() は、マップのシングルタップに応答します。このメソッドはタップされた場所の緯度と経度を受け取るため、その地点にパンまたはズームすることで応答できます。マーカーのバブルのタップやマーカーのドラッグ操作に対する応答でも、同様のメソッドを使用できます。

カメラの動きをリッスンして、カメラが動き始めたとき、現在動いているとき、または停止したときに、アプリが通知を受信するようにできます。詳しくは、カメラの変更イベントに関するガイドをご覧ください。

マップ上の建物の 3D 表示

多くの都市は、拡大表示していくと 3D の建物が表示されます。カナダのバンクーバーの画像の例を以下に示します。GoogleMap.setBuildingsEnabled(false) を呼び出すことで、建物の 3D 表示を無効にできます。

バンクーバー(カナダ)の地図

カメラの位置

マップビューは、平面を見下ろすカメラとしてモデル化されています。カメラの位置(したがってマップのレンダリング)は、target(緯度と経度の位置)bearingtiltzoom の各プロパティで指定されます。

カメラ プロパティの図

Target(位置)

カメラの target はマップの中心位置で、緯度と経度の座標で指定されます。

Bearing(向き)

カメラの bearing は、マップ上の垂直線が指し示す方向で、北からの時計回りの度数で表されます。車を運転する人の多くは、道路マップの向きを進行方向に合わせます。一方、マップとコンパスを使用するハイカーの多くは、垂直線が北を指すようにマップの向きを調整します。Maps API を使用すると、マップの向きを進行方向に合わせたり、方角を固定したりできます。たとえば、bearing を 90 度に変更すると、上方向が真東を指すようにマップの向きが変更されます。

Tilt(傾斜角、投影角または視角)

Tilt は、マップの中心の真上と地表面とを結ぶ円弧上にあるカメラの位置として定義され、天底(カメラの真下を指す方向)からの度数で示されます。角度を変更すると、遠くをより小さく、近くをより大きく描く透視投影法でマップが表示されます。以下の図でこれを示します。

以下の図の傾斜角は 0 度です。最初の図は、これを図解したものです。位置 1 がカメラの位置で、位置 2 が現在のマップの位置です。その下に、生成されるマップを示します。

傾斜角 0 度(平行投影)で設置したカメラによるズームレベル 18 でのマップのスクリーンショット。
カメラのデフォルトの傾斜角で表示されたマップ
角度 0 度で、カメラのデフォルト位置であるマップ位置の真上を表示する図。
カメラのデフォルトの傾斜角。

以下の図では、傾斜角が 45 度です。カメラが 45 度チルトしているのではなく、真上(0 度)と地面(90 度)を結ぶ円弧に沿って、位置 3 まで半分移動している点に注意してください。カメラがマップの中心点を指していることに変わりはありませんが、位置 4 の線で表される領域も視界に入っています。

傾斜角 45 度で設置したカメラによるズームレベル 18 でのマップのスクリーンショット。
傾斜角 45 度で表示されたマップ。
傾斜角 45 度で設置し、ズームレベルはそのまま 18 に設定されたカメラを示す図
傾斜角 45 度のカメラ。

このスクリーンショットのマップの中心は、元のマップと同じ地点に設定されていますが、マップの上部により多くの対象物が表示されています。角度を 45 度より大きくすると、カメラとマップ位置の間にある対象物が相対的に大きく表示され、マップ位置より後ろにある対象物は相対的に小さく表示されるようになるため、3 次元効果が生まれます。

Zoom(ズームレベル)

カメラのズームレベルにより、マップの倍率が決まります。ズームレベルが大きいほど、画面の表示はより詳細になり、ズームレベルが小さいほど、画面に世界のより多くの部分が表示されるようになります。ズームレベル 0 では、全世界の幅が約 256 dp(密度非依存ピクセル)になるようなマップの倍率になります。

ズームレベルを 1 上げるごとに、画面の世界の幅が 2 倍になります。 したがって、ズームレベル N では、世界の幅は約 256 * 2N dp になります。つまり、ズームレベル 2 では、全世界の幅は約 1024 dp です。ズームレベルは整数である必要はないことに注意してください。マップで許可されるズームレベルの範囲は、位置、マップタイプ、画面サイズといった複数の要因によって決まります。範囲外の数値は、それに最も近い有効な値(最小ズームレベルまたは最大ズームレベル)に変換されます。次のリストは、各ズームレベルで表示されるおおよその詳細度を示しています。

  • 1: 世界
  • 5: 大陸
  • 10: 都市
  • 15: 通り
  • 20: 建物

次の図は、異なるズームレベルの表示結果を示しています。

ズームレベル 5 のマップのスクリーンショット
ズームレベル 5 のマップ。
ズームレベル 15 のマップのスクリーンショット
ズームレベル 15 のマップ。
ズームレベル 20 のマップのスクリーンショット
ズームレベル 20 のマップ。

: デバイスによっては、その画面サイズと密度が最小ズームレベルをサポートできない場合があります。マップで指定可能な最小ズームレベルを取得するには、GoogleMap.getMinimumZoomLevel() を使用します。ビューポートに世界全体を表示する必要がある場合は、ライトモードの使用をおすすめします。

カメラの移動

Maps API を使用すると、世界のどの部分をマップに表示するかを変更できます。これを行うには、(マップを動かすのではなく)カメラの位置を変更します。

カメラを変更する際のオプションとして、カメラの移動にアニメーションを付けることができます。アニメーションによって、現在のカメラ属性から新しいカメラ属性にスムーズに表示が切り替わります。アニメーションの長さを調整することもできます。

カメラの位置を変更するには、CameraUpdate を使って、カメラの移動先を指定する必要があります。Maps API では、CameraUpdateFactory を使ってさまざまなタイプの CameraUpdate を作成できます。以下のオプションを使用できます。

ズームレベルの変更と最小 / 最大ズームの設定

CameraUpdateFactory.zoomIn()CameraUpdateFactory.zoomOut() を使用すると、その他すべてのプロパティは同じに保ったまま、ズームレベルを 1.0 変更する CameraUpdate が作成されます。

CameraUpdateFactory.zoomTo(float) を使用すると、その他すべてのプロパティは同じに保ったまま、ズームレベルを指定した値に変更する CameraUpdate が作成されます。

CameraUpdateFactory.zoomBy(float)CameraUpdateFactory.zoomBy(float, Point) を使用すると、ズームレベルを指定した値だけ上げる(または、負の値の場合は下げる)CameraUpdate が作成されます。後者は、画面上の指定した地点が同じ位置(緯度と経度)に留まるように固定してズームレベルを変更します。そのため、カメラの位置が変更されることがあります。

任意の最小または最大(またはその両方)のズームレベルを設定しておくと便利です。たとえば、アプリケーションで有名スポットの周りの指定された範囲を表示する場合や、限られたいくつかのズームレベルを使用したカスタム タイル オーバーレイを使用している場合に、ユーザー エクスペリエンスを制御するのに便利です。

Java

private GoogleMap map;
    map.setMinZoomPreference(6.0f);
    map.setMaxZoomPreference(14.0f);
      

Kotlin

private lateinit var map: GoogleMap

    map.setMinZoomPreference(6.0f)
    map.setMaxZoomPreference(14.0f)
      

技術的な問題により、API では極端に低いまたは高いズームレベルに対応できない場合があることに注意してください。たとえば、衛星マップや地形マップは、基本地図タイルよりも最大ズームレベルが低いことがあります。

カメラの位置の変更

一般的な位置の変更には、2 つの便利な方法があります。 CameraUpdateFactory.newLatLng(LatLng) を使用すると、その他すべてのプロパティは同じに保ったまま、カメラの緯度と経度を変更する CameraUpdate が作成されます。CameraUpdateFactory.newLatLngZoom(LatLng, float) を使用すると、その他すべてのプロパティは同じに保ったまま、カメラの緯度、経度、ズームを変更する CameraUpdate が作成されます。

カメラ位置の変更で完全な柔軟性を実現するには、カメラを指定した位置に移動する CameraUpdate を作成する CameraUpdateFactory.newCameraPosition(CameraPosition) を使用してください。CameraPosition は、new CameraPosition() を使って直接取得することも、new CameraPosition.Builder() を使って CameraPosition.Builder により取得することもできます。

パン表示(スクロール)

CameraUpdateFactory.scrollBy(float, float) を使用すると、指定されたピクセル数だけマップが移動するようにカメラの緯度と経度を変更する CameraUpdate が作成されます。正の x 値を指定するとカメラが右に移動するため、マップは左に移動したように見えます。正の y 値を指定すると、カメラが下に移動するため、マップが上に移動したように見えます。反対に、負の x 値を指定するとカメラが左に移動するため、マップが右に移動したように見え、負の y 値を指定するとカメラが上に移動します。スクロールは、カメラの現在の向きに相対的に行われます。たとえば、カメラの bearing が 90 度の場合、東が「上」です。

境界の設定

マップの境界を設定する

関心のある地域全体が可能な限り最大のズームレベルで表示されるようにカメラを移動すると便利なことがあります。たとえば、ユーザーの現在地から 8 km 以内にあるガソリン スタンドをすべて表示する場合、それらがすべて画面上に表示されるようにカメラを移動する必要があります。これを行うには、まず、画面に表示する LatLngBounds を計算します。次に、CameraUpdateFactory.newLatLngBounds(LatLngBounds bounds, int padding) を使って、計算した LatLngBounds が完全にマップ内に収まるようにカメラ位置を変更する CameraUpdate を取得します。パディングが指定されていれば(ピクセル単位)、それを考慮に入れてください。これにより、返される CameraUpdate では、指定された境界とマップの端との間のギャップ(ピクセル単位)が、パディングより大きい値に保たれます。なお、マップの tilt と bearing はいずれも 0 になることに注意してください。

Java

LatLngBounds australiaBounds = new LatLngBounds(
    new LatLng(-44, 113), // SW bounds
    new LatLng(-10, 154)  // NE bounds
);
map.moveCamera(CameraUpdateFactory.newLatLngBounds(australiaBounds, 0));
      

Kotlin

val australiaBounds = LatLngBounds(
    LatLng((-44.0), 113.0),  // SW bounds
    LatLng((-10.0), 154.0) // NE bounds
)
map.moveCamera(CameraUpdateFactory.newLatLngBounds(australiaBounds, 0))
      

範囲内でマップを中央に配置する

場合によっては、境界の端を指定するのではなく、ある範囲内でカメラを中心に設定したいことがあります。たとえば、ズームを一定に保ったまま、ある国の中心にカメラを設定する場合です。この場合は、LatLngBounds を作成してから CameraUpdateFactory.newLatLngZoom(LatLng latLng, float zoom)LatLngBounds.getCenter() メソッドを使用すると、同様のメソッドを使用できます。getCenter() メソッドは、LatLngBounds の地理的中心を返します。

Java

LatLngBounds australiaBounds = new LatLngBounds(
    new LatLng(-44, 113), // SW bounds
    new LatLng(-10, 154)  // NE bounds
);
map.moveCamera(CameraUpdateFactory.newLatLngZoom(australiaBounds.getCenter(), 10));
      

Kotlin

val australiaBounds = LatLngBounds(
    LatLng((-44.0), 113.0),  // SW bounds
    LatLng((-10.0), 154.0) // NE bounds
)
map.moveCamera(CameraUpdateFactory.newLatLngZoom(australiaBounds.center, 10f))
      

このメソッドのオーバーロード newLatLngBounds(boundary, width, height, padding) を使用すると、マップの寸法に対応する長方形の幅と高さをピクセル単位で指定できます。この長方形は、その中心がマップのビューの中心と同じになるように配置されます(そのため、指定された寸法がマップのビューの寸法と同じ場合、長方形がマップのビューと一致します)。返される CameraUpdate によって、必要なパディングを考慮したうえで、可能な限り最大のズームレベルで、画面上の長方形内の中心が指定された LatLngBounds になるようにカメラが移動されます。

注: マップのレイアウトを行った後でカメラを移動する場合は、より単純なメソッド newLatLngBounds(boundary, padding) のみを使用して CameraUpdate を生成し、これを使用してください。API はレイアウト中に、境界ボックスを正しく投影するために必要なマップの表示境界を計算します。一方、より複雑なメソッド newLatLngBounds(boundary, width, height, padding) によって返される CameraUpdate は、マップのレイアウトが完了する前を含め、いつでも使用できます。これは、API が、渡された引数から表示境界を計算するためです。

ユーザーによるパン操作を所定の領域に制限する

上述のシナリオではマップの境界を設定しましたが、ユーザーはこれらの境界の外側にマップをスクロールまたはパンできます。一方、マップの焦点の緯度 / 経度の中心領域(カメラ ターゲット)を制限すると、これらの境界内のみでユーザーによるスクロールやパンの操作を許可することができます。たとえば、ショッピング センターや空港向けの小売り用アプリでは、マップを特定の境界内に制限して、ユーザーがこれらの境界内でのみスクロールやパンの操作を行えるようにする必要がある場合があります。

Java

// Create a LatLngBounds that includes the city of Adelaide in Australia.
LatLngBounds adelaideBounds = new LatLngBounds(
    new LatLng(-35.0, 138.58), // SW bounds
    new LatLng(-34.9, 138.61)  // NE bounds
);

// Constrain the camera target to the Adelaide bounds.
map.setLatLngBoundsForCameraTarget(adelaideBounds);
      

Kotlin

// Create a LatLngBounds that includes the city of Adelaide in Australia.
val adelaideBounds = LatLngBounds(
    LatLng(-35.0, 138.58),  // SW bounds
    LatLng(-34.9, 138.61) // NE bounds
)

// Constrain the camera target to the Adelaide bounds.
map.setLatLngBoundsForCameraTarget(adelaideBounds)
      

次の図は、カメラ ターゲットがビューポートより若干大きな領域に制限されている場合のシナリオを示しています。カメラ ターゲットが境界領域内にある場合のみ、ユーザーはスクロールおよびパン操作を行うことができます。X は、カメラ ターゲットを表しています。

カメラの LatLngBounds がビューポートより広い場合の図。

マップは常にビューポート全体に表示されます。ビューポートは、定義された境界の外側の領域も表示します。たとえば、カメラ ターゲットを境界領域の角に置いた場合、その角を超えた領域もビューポートに表示されますが、ユーザーはその領域にスクロールまたはパンすることはできません。以下の図は、このシナリオを示しています。X はカメラ ターゲットを表しています。

カメラの LatLngBounds の右下角にカメラ ターゲットがある場合の図。

次の図では、カメラ ターゲットは非常に狭い境界内にあり、ユーザーはマップのスクロールまたはパン操作をほとんど行うことができません。X はカメラ ターゲットを表しています。

ビューポートより狭いカメラの LatLngBounds を示す図。

カメラビューの更新

CameraUpdate をマップに適用する場合、カメラをすぐに移動することも、アニメーションを付けてカメラをスムーズに移動することもできます。CameraUpdate を指定してカメラをすぐに移動する場合は、GoogleMap.moveCamera(CameraUpdate) を呼び出します。

特に短い移動の場合は、変更にアニメーションを付けることで、ユーザー エクスペリエンスをより楽しいものにできます。これを行うには、GoogleMap.moveCamera を呼び出す代わりに、GoogleMap.animateCamera を呼び出します。マップが新しい属性にスムーズに移動します。このメソッドの最も詳細な形式である GoogleMap.animateCamera(cameraUpdate, duration, callback) では、以下の 3 つの引数が提供されます。

cameraUpdate
CameraUpdate はカメラの移動先を示します。
callback
GoogleMap.CancellableCallback を実装するオブジェクト。 このタスクを処理するための一般化されたインターフェースは、`onCancel()` と `onFinished()` の 2 つのメソッドを定義します。アニメーションの場合、これらのメソッドは次の状況で呼び出されます。
onFinish()
アニメーションが中断なしで完了した場合に呼び出されます。
onCancel()

stopAnimation() の呼び出しか、新しいカメラの移動の開始によってアニメーションが中断された場合に呼び出されます。

または、GoogleMap.stopAnimation() を呼び出した場合にも呼び出されることがあります。

duration
アニメーションに必要な時間(ミリ秒単位)。int として指定します。

以下のコード スニペットには、カメラを移動するための一般的な方法がいくつか含まれています。

Java

LatLng sydney = new LatLng(-33.88,151.21);
LatLng mountainView = new LatLng(37.4, -122.1);

// Move the camera instantly to Sydney with a zoom of 15.
map.moveCamera(CameraUpdateFactory.newLatLngZoom(sydney, 15));

// Zoom in, animating the camera.
map.animateCamera(CameraUpdateFactory.zoomIn());

// Zoom out to zoom level 10, animating with a duration of 2 seconds.
map.animateCamera(CameraUpdateFactory.zoomTo(10), 2000, null);

// Construct a CameraPosition focusing on Mountain View and animate the camera to that position.
CameraPosition cameraPosition = new CameraPosition.Builder()
    .target(mountainView )      // Sets the center of the map to Mountain View
    .zoom(17)                   // Sets the zoom
    .bearing(90)                // Sets the orientation of the camera to east
    .tilt(30)                   // Sets the tilt of the camera to 30 degrees
    .build();                   // Creates a CameraPosition from the builder
map.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
      

Kotlin

val sydney = LatLng(-33.88, 151.21)
val mountainView = LatLng(37.4, -122.1)

// Move the camera instantly to Sydney with a zoom of 15.
map.moveCamera(CameraUpdateFactory.newLatLngZoom(sydney, 15f))

// Zoom in, animating the camera.
map.animateCamera(CameraUpdateFactory.zoomIn())

// Zoom out to zoom level 10, animating with a duration of 2 seconds.
map.animateCamera(CameraUpdateFactory.zoomTo(10f), 2000, null)

// Construct a CameraPosition focusing on Mountain View and animate the camera to that position.
val cameraPosition = CameraPosition.Builder()
    .target(mountainView) // Sets the center of the map to Mountain View
    .zoom(17f)            // Sets the zoom
    .bearing(90f)         // Sets the orientation of the camera to east
    .tilt(30f)            // Sets the tilt of the camera to 30 degrees
    .build()              // Creates a CameraPosition from the builder
map.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition))