攝影機和檢視畫面

選取平台: Android iOS JavaScript

使用者可透過簡單的手勢,傾斜及旋轉 Maps SDK for Android 地圖,自由調整方向。任何縮放等級都可以平移地圖或變更其視角,而因為向量地圖圖塊的記憶體使用量較小,很少出現延遲。

程式碼範例

GitHub 上的 ApiDemos 存放區有攝影機功能的說明範例:

簡介

和網頁版 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 則是目前地圖的位置。最終地圖則如下所示。

地圖螢幕截圖,攝影機採 0 度視角,縮放等級為 18。
以攝影機預設視角呈現的地圖。
圖表顯示攝影機預設位置在地圖位置正上方,角度為 0 度。
攝影機的預設視角。

在下圖中,視角為 45 度。請注意,攝影機沿著弧線移動到地圖正上方 (0 度) 和地面 (90 度) 中間,也就是 3 的位置。攝影機仍然指向地圖的中心點,但現在可以看到位置 4 的線條所代表的區域。

地圖螢幕截圖,攝影機採 45 度視角,縮放等級為 18。
以 45 度視角呈現的地圖。
圖表顯示攝影機視角為 45 度,縮放等級仍設為 18。
45 度的攝影機視角。

在此螢幕截圖中,地圖的中心點仍與原始地圖相同,但地圖頂端顯示了更多地圖項目。若您將視角調整至 45 度以上,攝影機和地圖位置之間的地圖項目看起來會較大,而地圖位置以外的地圖項目則看起來較小,因而產生 3D 效果。

縮放

地圖比例取決於攝影機的縮放等級。縮放等級較大時,螢幕上會顯示較多細節;縮放等級較小時,則能在螢幕上顯示較大的範圍。 縮放等級為 0 時,地圖比例是整個世界的寬度大約為 256dp (密度獨立像素)。

將縮放等級提升 1,螢幕上的世界寬度就會加倍。因此,縮放等級若為 N,世界的寬度就大約是 256 * 2N dp。舉例來說,縮放等級為 2 時,整個世界的寬度大約是 1024dp。

縮放等級不需要是整數。地圖允許的縮放等級範圍取決於許多因素,包括目標、地圖類型和螢幕大小。範圍外的任何數字都會轉換為下一個最接近的有效值,可能是最小或最大縮放等級。以下清單列出各縮放等級大致可顯示的精細程度:

  • 1:全世界
  • 5:自然景觀/大陸
  • 10:城市
  • 15:街道
  • 20:建築
下圖顯示不同縮放等級的視覺外觀:
縮放等級為 5 的地圖螢幕截圖
縮放等級為 5 的地圖。
縮放等級為 15 的地圖螢幕截圖
縮放等級為 15 的地圖。
縮放等級為 20 的地圖螢幕截圖
縮放等級為 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 並搭配使用 LatLngBoundsCameraUpdateFactory.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);

      

下圖說明將攝影機目標限制在比可視區域稍大範圍的情況。只要攝影機目標仍在限制區域內,使用者就能捲動及平移地圖。交叉符號代表攝影機目標:

顯示攝影機 LatLngBounds 大於可視區域的圖表。

即使可視區域會顯示超出定義邊界的區域,地圖仍會將可視區域填滿。舉例來說,如果您將攝影機目標放在限制區域的角落,可視區域中就會出現該角落以外的區域,但使用者無法捲動至該區域。請參考下圖說明。交叉符號代表攝影機目標:

顯示攝影機目標位於攝影機 LatLngBounds 右下角的圖表。

在下圖中,攝影機目標的範圍非常有限,因此使用者幾乎無法捲動或平移地圖。交叉符號代表攝影機目標:

顯示攝影機 LatLngBounds 小於可視區域的圖表。

更新攝影機畫面

如要為地圖套用 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));