Bạn có thể nghiêng và xoay bản đồ trong SDK Bản đồ dành cho Android bằng các cử chỉ dễ dàng, cho phép người dùng điều chỉnh bản đồ theo hướng phù hợp với họ. Ở bất kỳ cấp độ thu phóng nào, bạn cũng có thể kéo bản đồ hoặc thay đổi phối cảnh của bản đồ với độ trễ rất thấp nhờ kích thước nhỏ hơn của các ô bản đồ dựa trên vectơ.
Mã mẫu
Kho lưu trữ ApiDemos trên GitHub bao gồm một mẫu minh hoạ các tính năng của máy ảnh:
- CameraDemoActivity – Kotlin: Thay đổi vị trí của máy ảnh
- CameraDemoActivity – Java: Thay đổi vị trí máy ảnh
Giới thiệu
Giống như Google Maps trên web, SDK Maps cho Android thể hiện bề mặt của trái đất (một hình cầu) trên màn hình của thiết bị (một mặt phẳng) bằng cách sử dụng thuyết chiếu Mercator. Ở hướng đông và tây, bản đồ được lặp lại vô hạn khi thế giới bao bọc xung quanh chính nó một cách liền mạch. Ở hướng bắc và nam, bản đồ bị giới hạn ở khoảng 85 độ bắc và 85 độ nam.
Lưu ý: Chế độ chiếu Mercator có chiều rộng dọc có giới hạn nhưng chiều cao theo vĩ độ là vô hạn. Chúng tôi "cắt bỏ" hình ảnh bản đồ cơ sở bằng cách sử dụng phép chiếu Mercator ở khoảng +/- 85 độ để tạo hình dạng bản đồ hình vuông, giúp logic lựa chọn thẻ thông tin dễ dàng hơn.
SDK Bản đồ dành cho Android cho phép bạn thay đổi điểm nhìn của người dùng trên bản đồ bằng cách sửa đổi camera của bản đồ.
Những thay đổi đối với máy ảnh sẽ không ảnh hưởng đến các điểm đánh dấu, lớp phủ hoặc đồ hoạ khác mà bạn đã thêm, mặc dù bạn có thể muốn thay đổi nội dung bổ sung để phù hợp hơn với chế độ xem mới.
Vì có thể nghe các cử chỉ của người dùng trên bản đồ, nên bạn có thể thay đổi bản đồ để phản hồi các yêu cầu của người dùng. Ví dụ: phương thức gọi lại OnMapClickListener.onMapClick()
phản hồi một lần nhấn trên bản đồ. Vì phương thức này nhận được vĩ độ và kinh độ của vị trí nhấn, nên bạn có thể phản hồi bằng cách kéo hoặc thu phóng đến điểm đó.
Có các phương thức tương tự để phản hồi thao tác nhấn vào bong bóng của điểm đánh dấu hoặc để phản hồi cử chỉ kéo trên điểm đánh dấu.
Bạn cũng có thể theo dõi chuyển động của máy ảnh để ứng dụng của bạn nhận được thông báo khi máy ảnh bắt đầu di chuyển, đang di chuyển hoặc dừng di chuyển. Để biết thông tin chi tiết, hãy xem hướng dẫn về sự kiện thay đổi máy ảnh.
Vị trí máy ảnh
Chế độ xem bản đồ được mô phỏng như một máy ảnh nhìn xuống mặt phẳng. Vị trí của máy ảnh (và do đó là việc kết xuất bản đồ) được xác định bằng các thuộc tính sau: mục tiêu (vĩ độ/kinh độ của địa điểm), độ lệch, độ nghiêng và tỷ lệ thu phóng.
Mục tiêu (vị trí)
Mục tiêu của máy ảnh là vị trí của tâm bản đồ, được chỉ định dưới dạng toạ độ vĩ độ và kinh độ.
Vĩ độ có thể nằm trong khoảng từ -85 đến 85 độ. Các giá trị trên hoặc dưới phạm vi này sẽ được cố định thành giá trị gần nhất trong phạm vi này. Ví dụ: việc chỉ định vĩ độ 100 sẽ đặt giá trị thành 85. Kinh độ nằm trong khoảng từ -180 đến 180 độ. Các giá trị cao hơn hoặc thấp hơn phạm vi này sẽ được gói sao cho nằm trong phạm vi (-180, 180). Ví dụ: 480, 840 và 1200 đều sẽ được gói thành 120 độ.Phương vị (hướng)
Độ lệch của máy ảnh chỉ định hướng la bàn, được đo bằng độ từ hướng bắc thực, tương ứng với cạnh trên cùng của bản đồ. Nếu bạn vẽ một đường dọc từ tâm bản đồ đến cạnh trên cùng của bản đồ, thì góc phương vị sẽ tương ứng với hướng của máy ảnh (được đo bằng độ) so với hướng bắc thực.
Giá trị góc phương vị 0 có nghĩa là đầu bản đồ chỉ về hướng bắc thực. Giá trị góc phương vị 90 có nghĩa là đầu bản đồ chỉ về hướng đông (90 độ trên la bàn). Giá trị 180 có nghĩa là đầu bản đồ chỉ về phía nam.
API Maps cho phép bạn thay đổi hướng của bản đồ. Ví dụ: người lái xe thường xoay bản đồ đường để căn chỉnh với hướng di chuyển của họ, trong khi người đi bộ đường dài sử dụng bản đồ và la bàn thường định hướng bản đồ sao cho đường dọc chỉ về hướng bắc.
Nghiêng (góc nhìn)
Độ nghiêng xác định vị trí của máy ảnh trên một vòng cung ngay phía trên vị trí trung tâm của bản đồ, được đo bằng độ từ nadir (hướng chỉ thẳng xuống dưới máy ảnh). Giá trị 0 tương ứng với máy ảnh hướng thẳng xuống. Các giá trị lớn hơn 0 tương ứng với một máy ảnh được hướng về chân trời theo số độ được chỉ định. Khi bạn thay đổi góc nhìn, bản đồ sẽ xuất hiện theo phối cảnh, với các đối tượng ở xa sẽ xuất hiện nhỏ hơn và các đối tượng ở gần sẽ xuất hiện lớn hơn. Các hình minh hoạ sau đây minh hoạ điều này.
Trong các hình ảnh bên dưới, góc nhìn là 0 độ. Hình ảnh đầu tiên cho thấy sơ đồ của điều này; vị trí 1 là vị trí máy ảnh và vị trí 2 là vị trí bản đồ hiện tại. Bản đồ thu được sẽ xuất hiện bên dưới.
Trong hình ảnh bên dưới, góc nhìn là 45 độ. Lưu ý rằng máy ảnh di chuyển một nửa dọc theo một vòng cung giữa hướng thẳng lên trên (0 độ) và mặt đất (90 độ) đến vị trí 3. Máy ảnh vẫn đang hướng vào điểm trung tâm của bản đồ, nhưng khu vực được biểu thị bằng đường kẻ ở vị trí 4 hiện đã hiển thị.
Bản đồ trong ảnh chụp màn hình này vẫn được căn giữa ở cùng một điểm như trong bản đồ ban đầu, nhưng có nhiều đối tượng hơn xuất hiện ở đầu bản đồ. Khi bạn tăng góc ngoài 45 độ, các đối tượng giữa máy ảnh và vị trí trên bản đồ sẽ xuất hiện lớn hơn theo tỷ lệ, trong khi các đối tượng ngoài vị trí trên bản đồ sẽ xuất hiện nhỏ hơn theo tỷ lệ, tạo ra hiệu ứng ba chiều.
Zoom (thu phóng)
Mức thu phóng của máy ảnh xác định tỷ lệ của bản đồ. Ở các cấp độ thu phóng lớn hơn, bạn có thể thấy nhiều chi tiết hơn trên màn hình, trong khi ở các cấp độ thu phóng nhỏ hơn, bạn có thể thấy nhiều cảnh vật hơn trên màn hình. Ở mức thu phóng 0, tỷ lệ của bản đồ là toàn bộ thế giới có chiều rộng khoảng 256 dp (pixel không phụ thuộc vào mật độ).
Việc tăng cấp độ thu phóng thêm 1 sẽ làm tăng gấp đôi chiều rộng của thế giới trên màn hình. Do đó, ở cấp độ thu phóng N, chiều rộng của thế giới sẽ là khoảng 256 * 2N dp. Ví dụ: ở mức thu phóng 2, toàn bộ thế giới có chiều rộng khoảng 1024 dp.
Cấp độ thu phóng không cần phải là số nguyên. Phạm vi mức thu phóng mà bản đồ cho phép phụ thuộc vào một số yếu tố, bao gồm mục tiêu, loại bản đồ và kích thước màn hình. Mọi số nằm ngoài phạm vi này sẽ được chuyển đổi thành giá trị hợp lệ gần nhất tiếp theo, có thể là mức thu phóng tối thiểu hoặc mức thu phóng tối đa. Danh sách sau đây cho biết mức độ chi tiết gần đúng mà bạn có thể thấy ở mỗi cấp độ thu phóng:
- 1: Thế giới
- 5: Lục địa/châu lục
- 10: Thành phố
- 15: Đường phố
- 20: Toà nhà
Di chuyển máy ảnh
Maps API cho phép bạn thay đổi khu vực trên thế giới hiển thị trên bản đồ. Điều này được thực hiện bằng cách thay đổi vị trí của máy ảnh (thay vì di chuyển bản đồ).
Khi thay đổi máy ảnh, bạn có thể tạo ảnh động cho chuyển động của máy ảnh. Ảnh động nội suy giữa các thuộc tính máy ảnh hiện tại và các thuộc tính máy ảnh mới. Bạn cũng có thể kiểm soát thời lượng của ảnh động.
Để thay đổi vị trí của máy ảnh, bạn phải chỉ định vị trí bạn muốn di chuyển máy ảnh bằng CameraUpdate
. API Maps cho phép bạn tạo nhiều loại CameraUpdate
bằng cách sử dụng CameraUpdateFactory
. Bạn có các tuỳ chọn sau đây:
Thay đổi mức thu phóng và đặt mức thu phóng tối thiểu/tối đa
CameraUpdateFactory.zoomIn()
và CameraUpdateFactory.zoomOut()
cung cấp cho bạn một CameraUpdate
thay đổi mức thu phóng thêm 1,0, trong khi vẫn giữ nguyên tất cả các thuộc tính khác.
CameraUpdateFactory.zoomTo(float)
cung cấp cho bạn một CameraUpdate
thay đổi mức thu phóng thành giá trị đã cho, trong khi vẫn giữ nguyên tất cả các thuộc tính khác.
CameraUpdateFactory.zoomBy(float)
và CameraUpdateFactory.zoomBy(float, Point)
sẽ cung cấp cho bạn một CameraUpdate
giúp tăng (hoặc giảm, nếu giá trị là âm) mức thu phóng theo giá trị đã cho. Phương thức sau sửa điểm đã cho trên màn hình sao cho điểm đó vẫn ở cùng một vị trí (vĩ độ/kinh độ) và do đó có thể thay đổi vị trí của máy ảnh để đạt được điều này.
Bạn nên đặt mức thu phóng tối thiểu và/hoặc tối đa mà bạn muốn. Ví dụ: thông tin này hữu ích để kiểm soát trải nghiệm của người dùng nếu ứng dụng của bạn hiển thị một khu vực được xác định xung quanh một điểm yêu thích hoặc nếu bạn đang sử dụng lớp phủ thẻ thông tin tuỳ chỉnh với một bộ mức thu phóng có giới hạn.
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);
Xin lưu ý rằng có một số điểm cần cân nhắc về kỹ thuật có thể khiến API không cho phép người dùng thu phóng quá thấp hoặc quá cao. Ví dụ: hình ảnh vệ tinh hoặc địa hình có thể có mức thu phóng tối đa thấp hơn so với thẻ thông tin bản đồ cơ sở.
Thay đổi vị trí máy ảnh
Có hai phương thức thuận tiện cho các thay đổi vị trí phổ biến.
CameraUpdateFactory.newLatLng(LatLng)
cung cấp cho bạn một CameraUpdate
thay đổi vĩ độ và kinh độ của máy ảnh, đồng thời giữ nguyên tất cả các thuộc tính khác.
CameraUpdateFactory.newLatLngZoom(LatLng, float)
cung cấp cho bạn một CameraUpdate
thay đổi vĩ độ, kinh độ và độ thu phóng của máy ảnh, trong khi vẫn giữ nguyên tất cả các thuộc tính khác.
Để thay đổi vị trí máy ảnh một cách linh hoạt, hãy sử dụng CameraUpdateFactory.newCameraPosition(CameraPosition)
. Thao tác này sẽ cung cấp cho bạn CameraUpdate
để di chuyển máy ảnh đến vị trí đã cho. Bạn có thể lấy CameraPosition
trực tiếp bằng cách sử dụng new CameraPosition()
hoặc bằng CameraPosition.Builder
sử dụng new CameraPosition.Builder()
.
Kéo (cuộn)
CameraUpdateFactory.scrollBy(float, float)
cung cấp cho bạn một CameraUpdate
thay đổi vĩ độ và kinh độ của máy ảnh để bản đồ di chuyển theo số pixel được chỉ định. Giá trị x dương khiến máy ảnh di chuyển sang phải, do đó bản đồ có vẻ như đã di chuyển sang trái. Giá trị y dương sẽ khiến máy ảnh di chuyển xuống, vì vậy bản đồ có vẻ như đã di chuyển lên. Ngược lại, các giá trị x âm khiến máy ảnh di chuyển sang trái, vì vậy, bản đồ có vẻ như đã di chuyển sang phải và các giá trị y âm khiến máy ảnh di chuyển lên trên. Thao tác cuộn tương ứng với hướng hiện tại của máy ảnh. Ví dụ: nếu máy ảnh có góc phương vị là 90 độ, thì hướng đông sẽ là "lên".
Đặt ra ranh giới
Đặt ranh giới của bản đồ
Đôi khi, bạn nên di chuyển máy ảnh để toàn bộ khu vực mà bạn quan tâm xuất hiện ở mức thu phóng lớn nhất có thể. Ví dụ: nếu bạn đang hiển thị tất cả các trạm xăng trong phạm vi 8 km từ vị trí hiện tại của người dùng, thì bạn nên di chuyển máy ảnh để tất cả các trạm xăng đều hiển thị trên màn hình. Để làm việc này, trước tiên, hãy tính toán LatLngBounds
mà bạn muốn hiển thị trên màn hình. Sau đó, bạn có thể sử dụng CameraUpdateFactory.newLatLngBounds(LatLngBounds bounds, int
padding)
để lấy CameraUpdate
thay đổi vị trí máy ảnh sao cho LatLngBounds
đã cho vừa khít trong bản đồ, có tính đến khoảng đệm (tính bằng pixel) được chỉ định. CameraUpdate
được trả về đảm bảo rằng khoảng cách (tính bằng pixel) giữa các giới hạn đã cho và cạnh của bản đồ sẽ ít nhất bằng khoảng đệm được chỉ định. Xin lưu ý rằng độ nghiêng và góc phương vị của bản đồ đều sẽ là 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));
Đặt bản đồ ở giữa một khu vực
Trong một số trường hợp, bạn có thể muốn đặt máy ảnh ở giữa một giới hạn thay vì bao gồm cả các đường viền cực đoan. Ví dụ: để đặt máy ảnh ở giữa một quốc gia trong khi duy trì mức thu phóng không đổi. Trong trường hợp này, bạn có thể sử dụng một phương thức tương tự bằng cách tạo LatLngBounds
và sử dụng CameraUpdateFactory.newLatLngZoom(LatLng latLng, float zoom)
với LatLngBounds
.Phương thức getCenter()
. Phương thức getCenter() sẽ trả về tâm địa lý của 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));
Phương thức nạp chồng newLatLngBounds(boundary, width, height,
padding)
cho phép bạn chỉ định chiều rộng và chiều cao tính bằng pixel cho một hình chữ nhật, với ý định là các kích thước này tương ứng với kích thước của bản đồ. Hình chữ nhật được định vị sao cho tâm của hình chữ nhật giống với tâm của khung hiển thị bản đồ (vì vậy, nếu kích thước được chỉ định giống với kích thước của khung hiển thị bản đồ, thì hình chữ nhật sẽ trùng khớp với khung hiển thị bản đồ). CameraUpdate
được trả về sẽ di chuyển máy ảnh sao cho LatLngBounds
được chỉ định nằm ở giữa màn hình trong hình chữ nhật đã cho ở mức thu phóng lớn nhất có thể, có tính đến khoảng đệm bắt buộc.
Lưu ý: Chỉ sử dụng phương thức đơn giản hơn newLatLngBounds(boundary, padding)
để tạo CameraUpdate
nếu phương thức này sẽ được dùng để di chuyển máy ảnh sau khi bản đồ đã trải qua bố cục. Trong quá trình bố cục, API sẽ tính toán các ranh giới hiển thị của bản đồ cần thiết để chiếu chính xác hộp giới hạn. Để so sánh, bạn có thể sử dụng CameraUpdate
do phương thức phức tạp hơn newLatLngBounds(boundary, width, height, padding)
trả về bất cứ lúc nào, ngay cả trước khi bản đồ trải qua bố cục, vì API tính toán các ranh giới hiển thị từ các đối số mà bạn truyền.
Hạn chế thao tác kéo của người dùng ở một khu vực nhất định
Trong các trường hợp trên, bạn đặt giới hạn của bản đồ nhưng sau đó người dùng có thể cuộn hoặc kéo ra ngoài các giới hạn này. Thay vào đó, bạn nên ràng buộc các giới hạn trung tâm lat/lng của tâm điểm của bản đồ (mục tiêu của máy ảnh) để người dùng chỉ có thể cuộn và kéo trong các giới hạn này. Ví dụ: một ứng dụng bán lẻ cho trung tâm mua sắm hoặc sân bay có thể muốn ràng buộc bản đồ trong một giới hạn cụ thể, cho phép người dùng cuộn và kéo trong những giới hạn đó.
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);
Sơ đồ sau đây minh hoạ một tình huống khi mục tiêu của máy ảnh bị ràng buộc trong một khu vực lớn hơn một chút so với khung nhìn. Người dùng có thể cuộn và xoay, miễn là mục tiêu của máy ảnh vẫn nằm trong khu vực giới hạn. Dấu thập đại diện cho mục tiêu của máy ảnh:
Bản đồ luôn lấp đầy khung nhìn, ngay cả khi điều đó khiến khung nhìn hiển thị các khu vực nằm ngoài giới hạn đã xác định. Ví dụ: nếu bạn đặt mục tiêu của máy ảnh ở một góc của khu vực có giới hạn, thì khu vực bên ngoài góc đó sẽ hiển thị trong khung nhìn nhưng người dùng không thể cuộn vào khu vực đó. Sơ đồ sau đây minh hoạ trường hợp này. Dấu thập đại diện cho mục tiêu của máy ảnh:
Trong sơ đồ sau, mục tiêu của máy ảnh có giới hạn rất hạn chế, khiến người dùng có rất ít cơ hội cuộn hoặc xoay bản đồ. Dấu thập đại diện cho mục tiêu của máy ảnh:
Cập nhật chế độ xem máy ảnh
Để áp dụng CameraUpdate
cho bản đồ, bạn có thể di chuyển máy ảnh ngay lập tức hoặc tạo ảnh động cho máy ảnh một cách mượt mà. Để di chuyển máy ảnh ngay lập tức bằng CameraUpdate
đã cho, bạn có thể gọi GoogleMap.moveCamera(CameraUpdate)
.
Bạn có thể làm cho trải nghiệm người dùng trở nên dễ chịu hơn, đặc biệt là đối với các thao tác di chuyển ngắn, bằng cách tạo ảnh động cho sự thay đổi. Để thực hiện việc này, thay vì gọi GoogleMap.moveCamera
, hãy gọi GoogleMap.animateCamera
.
Bản đồ sẽ di chuyển liền mạch đến các thuộc tính mới. Biểu mẫu chi tiết nhất của phương thức này, GoogleMap.animateCamera(cameraUpdate, duration, callback)
, cung cấp 3 đối số:
cameraUpdate
CameraUpdate
mô tả vị trí di chuyển máy ảnh.callback
- Một đối tượng triển khai
GoogleMap.CancellableCallback
. Giao diện tổng quát này để xử lý các tác vụ xác định hai phương thức là `onCancel()` và `onFinished()`. Đối với ảnh động, các phương thức này được gọi trong các trường hợp sau:onFinish()
- Được gọi nếu ảnh động hoàn tất mà không bị gián đoạn.
onCancel()
-
Được gọi nếu ảnh động bị gián đoạn bằng cách gọi
stopAnimation()
hoặc bắt đầu một chuyển động máy ảnh mới.Ngoài ra, điều này cũng có thể xảy ra nếu bạn gọi
GoogleMap.stopAnimation()
.
duration
- Thời lượng mong muốn của ảnh động, tính bằng mili giây, dưới dạng
int
.
Các đoạn mã sau đây minh hoạ một số cách phổ biến để di chuyển máy ảnh.
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));