使用者可透過簡單的手勢,傾斜及旋轉 Maps SDK for Android 地圖,自由調整方向。任何縮放等級都可以平移地圖或變更其視角,而因為向量地圖圖塊的記憶體使用量較小,很少出現延遲。
程式碼範例
GitHub 上的 ApiDemos 存放區有攝影機功能的說明範例:
- CameraDemoActivity - Kotlin:變更攝影機位置
- CameraDemoActivity - Java:變更攝影機位置
簡介
和網頁版 Google 地圖一樣,Maps SDK for Android 使用麥卡托投影,在裝置的螢幕 (平面) 上呈現地球表面 (球體)。地圖會以東西向無限重複,因為地球本身就是無縫環繞的球體。地圖的南北向則限制在大約北緯 85 度和南緯 85 度以內。
注意:麥卡托投影的經度寬度有限制,但緯度高度則沒有限制。我們利用麥卡托投影法,在約正負 85 度的位置「裁切」基本地圖圖像,讓最終地圖呈正方形,以簡化選取圖塊的方式。
透過 Maps SDK for Android 調整地圖的攝影機,就能變更使用者查看地圖的視角。
調整攝影機不會變更已加入的標記、疊加層或其他圖形,不過建議您配合新視角修改加入的項目。
您可以監聽地圖上的使用者手勢,因應使用者的要求變更地圖。舉例來說,回呼方法 OnMapClickListener.onMapClick()
會回應地圖上的單次輕觸。這個方法會收到輕觸位置的經緯度,因此您可用平移或縮放至該點來回應。您可以利用其他類似方法,在使用者輕觸標記泡泡或對標記做出拖曳手勢時回應。
您也可以監聽攝影機動作,這樣當攝影機開始移動、正在移動或停止移動時,應用程式就會收到通知。詳情請參閱攝影機變更事件指南。
攝影機位置
地圖檢視是模擬向下俯瞰平面的攝影機。攝影機的位置 (以及連帶的地圖算繪方式) 是由下列屬性來指定:目標 (經緯度位置)、航向、傾斜角度和縮放。
目標 (位置)
攝影機目標是地圖的中心位置,透過經緯度座標指定。
緯度可以介於正負 85 度 (含首尾)。只要超出這個範圍,都會調整為範圍內最接近的值。舉例來說,如果將緯度指定為 100,值就會設為 85。經度的範圍介於正負 180 度 (含首尾)。凡是超出這個範圍,都會換算為範圍 (正負 180) 內的值。舉例來說,480、840 和 1200 都會換算為 120 度。航向 (方向)
攝影機航向指的是指南針方向 (以度為單位,從正北算起,對應至地圖頂端邊緣)。如果您從地圖的中心點到頂端邊緣繪製一條垂直線,航向會對應到相對於正北的攝影機方向 (以度為單位)。
航向 0 表示地圖頂端指向正北。航向值 90 表示地圖頂端朝向正東 (在指南針上顯示為 90 度),航向值 180 表示地圖頂端朝向正南。
Maps API 能讓您改變地圖的航向。舉例來說,駕駛人為了讓道路地圖和行進方向一致,常會翻轉地圖;健行的人如果把地圖和指南針搭配使用,通常會將地圖上的垂直線對準北方。
傾斜角度 (視角)
傾斜角度是指在地圖中心位置正上方的弧線上,從天底 (攝影機正下方) 測量至攝影機鏡頭位置所得的角度。值為 0 時,攝影機朝向正下方。值大於 0 時,攝影機依指定角度朝地平線傾斜。視角改變時,地圖的呈現會按照透視法調整,較遠的地圖項目看起來較小,鄰近的地圖項目看起來則較大。請參閱下方範例的說明。
在下圖中,視角為 0 度。第一張是相關示意圖,1 是攝影機位置,2 則是目前地圖的位置。最終地圖則如下所示。
在下圖中,視角為 45 度。請注意,攝影機沿著弧線移動到地圖正上方 (0 度) 和地面 (90 度) 中間,也就是 3 的位置。攝影機仍然指向地圖的中心點,但現在可以看到位置 4 的線條所代表的區域。
在此螢幕截圖中,地圖的中心點仍與原始地圖相同,但地圖頂端顯示了更多地圖項目。若您將視角調整至 45 度以上,攝影機和地圖位置之間的地圖項目看起來會較大,而地圖位置以外的地圖項目則看起來較小,因而產生 3D 效果。
縮放
地圖比例取決於攝影機的縮放等級。縮放等級較大時,螢幕上會顯示較多細節;縮放等級較小時,則能在螢幕上顯示較大的範圍。 縮放等級為 0 時,地圖比例是整個世界的寬度大約為 256dp (密度獨立像素)。
將縮放等級提升 1,螢幕上的世界寬度就會加倍。因此,縮放等級若為 N,世界的寬度就大約是 256 * 2N dp。舉例來說,縮放等級為 2 時,整個世界的寬度大約是 1024dp。
縮放等級不需要是整數。地圖允許的縮放等級範圍取決於許多因素,包括目標、地圖類型和螢幕大小。範圍外的任何數字都會轉換為下一個最接近的有效值,可能是最小或最大縮放等級。以下清單列出各縮放等級大致可顯示的精細程度:
- 1:全世界
- 5:自然景觀/大陸
- 10:城市
- 15:街道
- 20:建築
移動攝影機
Maps API 可讓您調整要在地圖上顯示世界的哪個部分。方法是變更攝影機的位置 (而不是移動地圖)。
調整攝影機時,您可以選擇是否要為產生的攝影機動作加入動畫效果。動畫會插入目前攝影機屬性和新攝影機屬性之間。您也可以控制動畫的時間長度。
如要變更攝影機的位置,請務必使用 CameraUpdate
指定您要將攝影機移動到何處。Maps API 可讓您使用 CameraUpdateFactory
建立許多不同類型的 CameraUpdate
。可用選項如下所示:
變更縮放等級和設定最小/最大縮放等級
CameraUpdateFactory.zoomIn()
和 CameraUpdateFactory.zoomOut()
會提供 CameraUpdate
,讓您以 1.0 為單位調整縮放等級,所有其他屬性則保持不變。
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 可能無法讓使用者過度放大或縮小地圖。舉例來說,衛星地圖或地形圖的最高縮放等級可能低於基本地圖圖塊。
變更攝影機位置
一般的位置變更可以透過兩個簡易做法完成。CameraUpdateFactory.newLatLng(LatLng)
會提供 CameraUpdate
來更改攝影機的緯度和經度,同時保留所有其他屬性。CameraUpdateFactory.newLatLngZoom(LatLng, float)
提供的 CameraUpdate
,可讓您變更攝影機的緯度、經度和縮放,同時保留所有其他屬性。
如想隨心所欲地變更攝影機位置,只要使用 CameraUpdateFactory.newCameraPosition(CameraPosition)
,即可透過 CameraUpdate
將攝影機移至指定位置。您也可以使用 new CameraPosition()
,或搭配 CameraPosition.Builder
使用 new CameraPosition.Builder()
,直接取得 CameraPosition
。
平移 (捲動)
CameraUpdateFactory.scrollBy(float, float)
提供 CameraUpdate
讓您改變攝影機的經緯度,以便地圖以指定的像素數進行偏移。正的 x 值會使攝影機向右移動,因此地圖看起來會向左移。正的 y 值會使攝影機向下移動,因此地圖看起來會向上移。相反地,負的 x 值會使攝影機向左移動,因此地圖看起來會向右移;負的 y 值則會使攝影機向上移動。捲動的方向是相對於攝影機目前的方向。舉例來說,如果攝影機的航向為 90 度,「上方」就是東方。
設定界線
設定地圖邊界
移動攝影機使整個搜尋區域以最大縮放等級顯示在地圖上,有時是很實用的做法。比方說,如果您要顯示使用者目前位置周圍五英里內的所有加油站,就可以移動攝影機,讓所有加油站都顯示在畫面中。做法如下:首先計算要顯示在畫面上的 LatLngBounds
。接著,您可以使用 CameraUpdateFactory.newLatLngBounds(LatLngBounds bounds, int
padding)
取得 CameraUpdate
來改變攝影機位置,讓指定的 LatLngBounds
能符合整個地圖的大小,同時將指定的邊框間距 (以像素為單位) 納入考量。傳回的 CameraUpdate
會確保指定邊界和地圖邊緣之間的間距 (以像素為單位) 至少為指定的邊框間距。注意,地圖的傾斜和方位角度都會是 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
並搭配使用 LatLngBounds
和 CameraUpdateFactory.newLatLngZoom(LatLng latLng, float zoom)
.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);
下圖說明將攝影機目標限制在比可視區域稍大範圍的情況。只要攝影機目標仍在限制區域內,使用者就能捲動及平移地圖。交叉符號代表攝影機目標:
即使可視區域會顯示超出定義邊界的區域,地圖仍會將可視區域填滿。舉例來說,如果您將攝影機目標放在限制區域的角落,可視區域中就會出現該角落以外的區域,但使用者無法捲動至該區域。請參考下圖說明。交叉符號代表攝影機目標:
在下圖中,攝影機目標的範圍非常有限,因此使用者幾乎無法捲動或平移地圖。交叉符號代表攝影機目標:
更新攝影機畫面
如要為地圖套用 CameraUpdate
,您可以立即移動攝影機,或加入動畫效果讓攝影機流暢地移動。如要利用指定的 CameraUpdate
立即移動攝影機,請呼叫 GoogleMap.moveCamera(CameraUpdate)
。
您可以為攝影機移動加入動畫效果來打造更賞心悅目的使用者體驗,特別是移動距離很短時。如要加入動畫,請不要呼叫 GoogleMap.moveCamera
,而應呼叫 GoogleMap.animateCamera
。
地圖就會流暢地移至新屬性。此方法最詳盡的形式 GoogleMap.animateCamera(cameraUpdate, duration, callback)
提供了三個引數:
cameraUpdate
CameraUpdate
說明攝影機移動的目的地。callback
- 導入
GoogleMap.CancellableCallback
的物件。 這個通用的工作處理介面會定義兩個方法,分別是 onCancel() 和 onFinished()。系統會根據動畫執行的情況呼叫這些方法,說明如下: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));