傾斜も回転も簡単な操作で行える Maps SDK for Android の地図では、ユーザーは見たい向きに地図を調整できます。ベクターベースの地図タイルはフットプリントが小さく、どのズームレベルで地図をパンしても視点を変更しても、遅延はほとんど生じません。
コードサンプル
GitHub の ApiDemos リポジトリには、カメラの機能を示すサンプルが含まれています。
- CameraDemoActivity - Kotlin: カメラ位置を変更する
- CameraDemoActivity - Java: カメラ位置を変更する
はじめに
ウェブの Google マップと同様に、Maps SDK for Android では、メルカトル図法を使ってデバイスの画面(平面)上に世界の表面(球面)を表します。世界は継ぎ目なく球面を包むように存在しているため、東と西の方向には、地図が無限に繰り返されます。北と南の方向では、地図が約 85 度北と 85 度南までに制限されています。
注: メルカトル図法では、経度を表す幅は有限ですが、緯度を表す高さは無限です。そこで、最終的な地図の形が正方形になるように、メルカトル図法を利用して約 +/- 85 度で基本地図の画像を切り取っています。これにより、タイル選択が簡単になります。
Maps SDK for Android では、地図のカメラを変更することで、ユーザーの視点位置を変更できます。
カメラに変更を加えても、追加したマーカーやオーバーレイなどのグラフィックは変更されませんが、新しいビューでより適切に表示されるようにこれらを変更するほうがよい場合があります。
地図でのユーザー操作をリッスンすることができるため、ユーザーの要求に応じて地図を変更できます。たとえば、コールバック メソッド OnMapClickListener.onMapClick()
は、地図のシングルタップに応答します。このメソッドはタップされた場所の緯度と経度を受け取るため、その地点にパンまたはズームすることで応答できます。マーカーのバブルのタップやマーカーのドラッグ操作に対する応答でも、同様のメソッドを使用できます。
カメラの動きをリッスンして、カメラが動き始めたとき、現在動いているとき、または停止したときに、アプリが通知を受信するようにできます。詳しくは、カメラの変更イベントに関するガイドをご覧ください。
カメラの位置
地図ビューは、平面を見下ろすカメラとしてモデル化されています。カメラの位置は(したがって地図のレンダリングも)、target(緯度と経度の位置)、bearing、tilt、zoom の各プロパティで指定されます。
target(位置)
カメラの target は地図の中心位置で、緯度と経度の座標で指定されます。
緯度は、-85~85 度の範囲で指定できます。この範囲以外の値は、この範囲内の最も近い値に設定されます。たとえば、緯度 100 を指定した場合は、値が 85 に設定されます。経度は -180~180 度の範囲になります。この範囲以外の値は、-180~180 の範囲内に収まるように変換されます。たとえば、480、840、1200 はすべて、120 度に変換されます。bearing(向き)
カメラの bearing は、コンパス方位を真北(地図の上端に対応)からの角度で示したものです。地図の中央から地図上端に向かって垂直線を引いた場合、bearing はカメラの向き(heading)を真北からの相対的な角度で示したものに対応します。
bearing が 0 なら、地図の上端が真北を指していることを意味します。bearing の値が 90 なら、地図の上端は真東(コンパスで 90 度)を指していることを意味します。値が 180 なら、地図の上端は真南を指します。
Maps API では、地図の bearing を変更することが可能です。車を運転する人の多くは、道路地図の向きを進行方向に合わせます。一方、地図とコンパスを使用するハイカーの多くは、垂直線が北を指すように地図の向きを設定します。
tilt(傾斜角、投影角または視角)
tilt は、地図の中心の真上を通る円弧上にあるカメラの位置として定義され、天底(カメラの真下を指す方向)からの度数で示されます。値が 0 なら、カメラが真下を向いていることを意味します。値を 0 より大きくすると、カメラはその角度の分だけ水平線に向かって円弧上を移動し、傾いていきます。角度を変更すると、遠くをより小さく、近くをより大きく描く透視投影法で地図が表示されます。以下の図でこれを示します。
以下の図の傾斜角は 0 度です。最初の図は、これを図解したものです。位置 1 がカメラの位置で、位置 2 が現在の地図の位置です。その下に、生成される地図を示します。
以下の図では、傾斜角が 45 度です。カメラが真上(0 度)と地面(90 度)を結ぶ円弧に沿って、位置 3 まで半分移動している点に注意してください。カメラが地図の中心点を指していることに変わりはありませんが、位置 4 の線で表される領域も視界に入っています。
このスクリーンショットの地図の中心は、元の地図と同じ地点に設定されていますが、地図の上部により多くの対象物が表示されています。角度を 45 度より大きくすると、カメラと地図位置の間にある対象物が相対的に大きく表示され、地図位置より後ろにある対象物は相対的に小さく表示されるようになるため、3 次元効果が生まれます。
zoom(ズームレベル)
カメラのズームレベルにより、地図の縮尺が決まります。ズームレベルが大きいほど画面の表示はより詳細になり、ズームレベルが小さいほど表示される地域が広くなります。ズームレベル 0 では、全世界の幅が約 256 dp(密度非依存ピクセル)になるような縮尺の地図が表示されます。
ズームレベルを 1 上げるごとに、画面の世界の幅が 2 倍になります。したがって、ズームレベル N では、世界の幅は約 256 * 2N dp になります。つまり、ズームレベル 2 では、全世界の幅は約 1024 dp です。
ズームレベルを整数にする必要はありません。地図で許可されるズームレベルの範囲は、target、地図タイプ、画面サイズといった複数の要因によって決まります。範囲外の数値は、それに最も近い有効な値(最小ズームレベルまたは最大ズームレベル)に変換されます。次のリストは、各ズームレベルで表示されるおおよその詳細度を示しています。
- 1: 世界
- 5: 大陸
- 10: 都市
- 15: 通り
- 20: 建物
カメラの移動
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
が作成されます。後者は、画面上の指定した地点が同じ位置(緯度と経度)に留まるように固定してズームレベルを変更します。そのため、カメラの位置が変更されることがあります。
任意の最小または最大(またはその両方)のズームレベルを設定しておくと便利です。たとえば、アプリケーションで有名スポットの周りの指定された範囲を表示する場合や、限られたいくつかのズームレベルを使用したカスタム タイル オーバーレイを使用している場合に、ユーザー エクスペリエンスを制御するのに便利です。
Kotlin
private lateinit var map: GoogleMap map.setMinZoomPreference(6.0f) map.setMaxZoomPreference(14.0f)
Java
private GoogleMap map; 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 になることに注意してください。
Kotlin
val australiaBounds = LatLngBounds( LatLng((-44.0), 113.0), // SW bounds LatLng((-10.0), 154.0) // NE bounds ) map.moveCamera(CameraUpdateFactory.newLatLngBounds(australiaBounds, 0))
Java
LatLngBounds australiaBounds = new LatLngBounds( new LatLng(-44, 113), // SW bounds new LatLng(-10, 154) // NE bounds ); map.moveCamera(CameraUpdateFactory.newLatLngBounds(australiaBounds, 0));
範囲内で地図を中央に配置する
場合によっては、境界の端を指定するのではなく、ある範囲内でカメラを中心に設定したいことがあります。たとえば、ズームを一定に保ったまま、ある国の中心にカメラを設定する場合です。この場合は、LatLngBounds
を作成してから CameraUpdateFactory.newLatLngZoom(LatLng latLng, float zoom)
と LatLngBounds
.getCenter()
メソッドを使用すると、同様のメソッドを使用できます。getCenter() メソッドは、LatLngBounds
の地理的中心を返します。
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))
Java
LatLngBounds australiaBounds = new LatLngBounds( new LatLng(-44, 113), // SW bounds new LatLng(-10, 154) // NE bounds ); map.moveCamera(CameraUpdateFactory.newLatLngZoom(australiaBounds.getCenter(), 10));
このメソッドのオーバーロード newLatLngBounds(boundary, width, height,
padding)
を使用すると、地図の寸法に対応する長方形の幅と高さをピクセル単位で指定できます。この長方形は、その中心が地図のビューの中心と同じになるように配置されます(そのため、指定された寸法が地図のビューの寸法と同じ場合、長方形が地図のビューと一致します)。返される CameraUpdate
によって、必要なパディングを考慮したうえで、可能な限り最大のズームレベルで、画面上の長方形内の中心が指定された LatLngBounds
になるようにカメラが移動されます。
注: 地図のレイアウトを行った後でカメラを移動する場合は、より単純なメソッド newLatLngBounds(boundary, padding)
のみを使用して CameraUpdate
を生成し、これを使用してください。API はレイアウト中に、境界ボックスを正しく投影するために必要な地図の表示境界を計算します。一方、より複雑なメソッド newLatLngBounds(boundary, width, height, padding)
によって返される CameraUpdate
は、地図のレイアウトが完了する前を含め、いつでも使用できます。これは、API が、渡された引数から表示境界を計算するためです。
ユーザーによるパン操作を所定の領域に制限する
上述のシナリオでは地図の境界を設定しましたが、ユーザーはこれらの境界の外側に地図をスクロールまたはパンできます。一方、地図の焦点の緯度 / 経度の中心領域(カメラ ターゲット)を制限すると、これらの境界内のみでユーザーによるスクロールやパンの操作を許可することができます。たとえば、ショッピング センターや空港向けの小売り用アプリでは、地図を特定の境界内に制限して、ユーザーがこれらの境界内でのみスクロールやパンの操作を行えるようにする必要がある場合があります。
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)
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);
次の図は、カメラ ターゲットがビューポートより若干大きな領域に制限されている場合のシナリオを示しています。カメラ ターゲットが境界領域内にある場合のみ、ユーザーはスクロールおよびパン操作を行うことができます。X は、カメラ ターゲットを表しています。
地図は常にビューポート全体に表示されます。ビューポートは、定義された境界の外側の領域も表示します。たとえば、カメラ ターゲットを境界領域の角に置いた場合、その角を超えた領域もビューポートに表示されますが、ユーザーはその領域にスクロールまたはパンすることはできません。以下の図は、このシナリオを示しています。X はカメラ ターゲットを表しています。
次の図では、カメラ ターゲットは非常に狭い境界内にあり、ユーザーは地図のスクロールまたはパン操作をほとんど行うことができません。X はカメラ ターゲットを表しています。
カメラビューの更新
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
として指定します。
以下のコード スニペットには、カメラを移動するための一般的な方法がいくつか含まれています。
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))
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));