Android nâng cao trong Kotlin 04.1: Android Google Maps

Lớp học lập trình này nằm trong khoá học Kotlin nâng cao cho Android. Bạn sẽ nhận được nhiều giá trị nhất qua khoá học này nếu thực hiện các lớp học lập trình theo trình tự, nhưng đó không phải là yêu cầu bắt buộc. Tất cả các lớp học lập trình của khoá học đều được liệt kê trên trang đích của lớp học lập trình Kiến thức nâng cao về cách tạo ứng dụng Android bằng Kotlin.

Khi tạo ứng dụng bằng Google Maps, bạn có thể thêm các tính năng vào ứng dụng của mình, chẳng hạn như hình ảnh vệ tinh, các chế độ kiểm soát giao diện người dùng mạnh mẽ cho bản đồ, tính năng theo dõi vị trí và điểm đánh dấu vị trí. Bạn có thể tăng giá trị cho Google Maps tiêu chuẩn bằng cách hiển thị thông tin từ tập dữ liệu của riêng bạn, chẳng hạn như vị trí của các khu vực câu cá hoặc leo núi nổi tiếng. Bạn cũng có thể tạo những trò chơi mà người chơi khám phá thế giới thực, chẳng hạn như trò chơi săn tìm kho báu hoặc thậm chí là trò chơi thực tế tăng cường.

Trong bài học này, bạn sẽ tạo một ứng dụng Google Maps có tên là Wander. Ứng dụng này hiển thị bản đồ tuỳ chỉnh và cho biết vị trí của người dùng.

Điều kiện tiên quyết

Có kiến thức về những điều sau:

  • Cách tạo một ứng dụng Android cơ bản và chạy ứng dụng đó bằng Android Studio.
  • Cách tạo và quản lý tài nguyên, chẳng hạn như chuỗi.
  • Cách tái cấu trúc mã và đổi tên biến bằng Android Studio.
  • Cách sử dụng bản đồ trên Google với tư cách là người dùng.
  • Cách đặt quyền khi bắt đầu chạy.

Kiến thức bạn sẽ học được

  • Cách lấy khoá API từ Google API Console và đăng ký khoá cho ứng dụng của bạn
  • Cách tích hợp Google Maps vào ứng dụng
  • Cách hiển thị các loại bản đồ
  • Cách định kiểu cho Google Maps
  • Cách thêm điểm đánh dấu vào bản đồ
  • Cách cho phép người dùng đặt điểm đánh dấu trên một địa điểm yêu thích (POI)
  • Cách bật tính năng theo dõi vị trí
  • Cách tạo ứng dụng Wander có bản đồ Google được nhúng
  • Cách tạo các tính năng tuỳ chỉnh cho ứng dụng của bạn, chẳng hạn như điểm đánh dấu và kiểu
  • Cách bật tính năng theo dõi vị trí trong ứng dụng

Trong lớp học lập trình này, bạn sẽ tạo ứng dụng Wander. Ứng dụng này hiển thị một bản đồ Google có kiểu tuỳ chỉnh. Ứng dụng Wander cho phép bạn thả điểm đánh dấu vào các vị trí, thêm lớp phủ và xem vị trí của bạn theo thời gian thực.

SDK Maps dành cho Android yêu cầu có khoá API. Để lấy khoá API, hãy đăng ký dự án của bạn trong trang API và Dịch vụ. Khoá API được liên kết với một chứng chỉ kỹ thuật số, giúp liên kết ứng dụng với tác giả của ứng dụng. Để biết thêm thông tin về cách sử dụng chứng chỉ kỹ thuật số và ký ứng dụng, hãy xem bài viết Ký ứng dụng.

Trong lớp học lập trình này, bạn sẽ sử dụng khoá API cho chứng chỉ gỡ lỗi. Theo thiết kế, chứng chỉ gỡ lỗi không an toàn, như mô tả trong phần Ký bản gỡ lỗi. Các ứng dụng Android đã xuất bản sử dụng Maps SDK cho Android cần có khoá API thứ hai: khoá cho chứng chỉ phát hành. Để biết thêm thông tin về cách lấy chứng chỉ phát hành, hãy xem phần Lấy khoá API.

Android Studio có một mẫu Google Maps Activity (Hoạt động trên Google Maps) giúp tạo mã mẫu hữu ích. Mã mẫu bao gồm một tệp google_maps_api.xml chứa một đường liên kết giúp đơn giản hoá việc lấy khoá API.

Bước 1: Tạo dự án Wander bằng mẫu bản đồ

  1. Tạo một dự án Android Studio mới.
  2. Chọn mẫu Hoạt động trên Google Maps.

  1. Đặt tên cho dự án Wander.
  2. Đặt cấp độ API tối thiểu thành API 19. Đảm bảo ngôn ngữ là Kotlin.
  3. Nhấp vào Hoàn tất.
  4. Sau khi ứng dụng hoàn tất quá trình tạo, hãy xem dự án của bạn và các tệp liên quan đến bản đồ sau đây mà Android Studio tạo cho bạn:

google_maps_api.xml – Bạn dùng tệp cấu hình này để lưu trữ khoá API. Mẫu này tạo ra hai tệp google_maps_api.xml: một tệp để gỡ lỗi và một tệp để phát hành. Tệp chứa khoá API cho chứng chỉ gỡ lỗi nằm trong src/debug/res/values. Tệp cho khoá API của chứng chỉ phát hành nằm trong src/release/res/values. Trong lớp học lập trình này, bạn chỉ sử dụng chứng chỉ gỡ lỗi.

activity_maps.xml – Tệp bố cục này chứa một mảnh duy nhất lấp đầy toàn bộ màn hình. Lớp SupportMapFragment là một lớp con của lớp Fragment. SupportMapFragment là cách đơn giản nhất để đặt bản đồ trong một ứng dụng. Đây là một trình bao bọc xung quanh khung hiển thị của bản đồ để tự động xử lý các nhu cầu cần thiết trong vòng đời.

Bạn có thể thêm SupportMapFragment vào tệp bố cục bằng cách sử dụng thẻ <fragment> trong bất kỳ ViewGroup nào, cùng với thuộc tính name bổ sung.

android:name="com.google.android.gms.maps.SupportMapFragment"

MapsActivity.java – Tệp MapsActivity.kt khởi tạo SupportMapFragment trong phương thức onCreate() và sử dụng getMapAsync() của lớp để tự động khởi chạy hệ thống bản đồ và khung hiển thị. Hoạt động chứa SupportMapFragment phải triển khai giao diện OnMapReadyCallback và phương thức onMapReady() của giao diện đó. Phương thức onMapReady() được gọi khi bản đồ được tải.

Bước 2: Lấy khoá API

  1. Mở phiên bản gỡ lỗi của tệp google_maps_api.xml.
  2. Trong tệp, hãy tìm một bình luận có URL dài. Các tham số của URL bao gồm thông tin cụ thể về ứng dụng của bạn.
  3. Sao chép và dán URL vào trình duyệt.
  4. Làm theo lời nhắc để tạo một dự án trên trang API và Dịch vụ. Nhờ các tham số trong URL được cung cấp, trang này biết cách tự động bật Maps SDK cho Android.
  5. Nhấp vào Tạo khoá API.
  6. Trên trang tiếp theo, hãy chuyển đến phần API Keys (Khoá API) rồi nhấp vào khoá mà bạn vừa tạo.
  7. Nhấp vào Hạn chế khoá rồi chọn Maps SDK cho Android để hạn chế việc sử dụng khoá cho các ứng dụng Android.
  8. Sao chép khoá API đã tạo. Cuộc họp này bắt đầu lúc AIza".
  9. Trong tệp google_maps_api.xml, hãy dán khoá vào chuỗi google_maps_key tại vị trí có nội dung YOUR_KEY_HERE.
  10. Chạy ứng dụng. Bạn sẽ thấy một bản đồ được nhúng trong hoạt động của mình với một điểm đánh dấu được đặt ở Sydney, Úc. (Điểm đánh dấu Sydney là một phần của mẫu và bạn sẽ thay đổi điểm đánh dấu này sau.)

Bước 3: Đổi tên mMap

MapsActivity có một lateinit var riêng tư tên là mMap, thuộc loại GoogleMap. Để tuân theo quy ước đặt tên của Kotlin, hãy đổi tên mMap thành map.

  1. Trong MapsActivity, hãy nhấp chuột phải vào mMap rồi nhấp vào Refactor (Tái cấu trúc) > Rename...(Đổi tên...)

  1. Đổi tên biến thành map.

Lưu ý cách tất cả các tham chiếu đến mMap trong hàm onMapReady() cũng thay đổi thành map.

Google Maps có nhiều loại bản đồ: bình thường, kết hợp, vệ tinh, địa hình và "không có" (không có bản đồ).

Bản đồ pháp tuyến

Bản đồ vệ tinh

Bản đồ kết hợp

Bản đồ địa hình

Mỗi loại bản đồ cung cấp các loại thông tin khác nhau. Ví dụ: khi sử dụng bản đồ để chỉ đường trong ô tô, bạn nên xem tên đường phố, vì vậy, bạn có thể sử dụng chế độ bình thường. Khi bạn đi bộ đường dài, bản đồ địa hình có thể giúp bạn quyết định xem bạn phải leo thêm bao nhiêu nữa để lên đến đỉnh.

Trong nhiệm vụ này, bạn sẽ:

  1. Thêm một thanh ứng dụng có trình đơn tuỳ chọn cho phép người dùng thay đổi loại bản đồ.
  2. Di chuyển vị trí bắt đầu của bản đồ đến vị trí nhà riêng của bạn.
  3. Thêm chế độ hỗ trợ cho các điểm đánh dấu, cho biết các vị trí riêng lẻ trên bản đồ và có thể bao gồm một nhãn.

Thêm trình đơn cho các loại bản đồ

Trong bước này, bạn sẽ thêm một thanh ứng dụng có trình đơn tuỳ chọn cho phép người dùng thay đổi loại bản đồ.

  1. Để tạo một tệp XML trình đơn mới, hãy nhấp chuột phải vào thư mục res rồi chọn New > Android Resource File (Tệp tài nguyên Android).
  2. Trong hộp thoại, hãy đặt tên tệp là map_options.
  3. Chọn Trình đơn cho loại tài nguyên.
  4. Nhấp vào OK.
  5. Trong thẻ Code (Mã), hãy thay thế mã trong tệp mới bằng đoạn mã sau để tạo các lựa chọn trong trình đơn bản đồ. Loại bản đồ "none" bị bỏ qua vì "none" dẫn đến việc không có bản đồ nào cả. Bước này gây ra lỗi, nhưng bạn sẽ giải quyết lỗi đó trong bước tiếp theo.
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto">
   <item
       android:id="@+id/normal_map"
       android:title="@string/normal_map"
       app:showAsAction="never" />
   <item
       android:id="@+id/hybrid_map"
       android:title="@string/hybrid_map"
       app:showAsAction="never" />
   <item
       android:id="@+id/satellite_map"
       android:title="@string/satellite_map"
       app:showAsAction="never" />
   <item
       android:id="@+id/terrain_map"
       android:title="@string/terrain_map"
       app:showAsAction="never" />
</menu>
  1. Trong strings.xml, hãy thêm tài nguyên cho các thuộc tính title để giải quyết lỗi.
<resources>
   ...
   <string name="normal_map">Normal Map</string>
   <string name="hybrid_map">Hybrid Map</string>
   <string name="satellite_map">Satellite Map</string>
   <string name="terrain_map">Terrain Map</string>
   <string name="lat_long_snippet">Lat: %1$.5f, Long: %2$.5f</string>
   <string name="dropped_pin">Dropped Pin</string>
   <string name="poi">poi</string>
</resources>
  1. Trong MapsActivity, hãy ghi đè phương thức onCreateOptionsMenu() và tăng cường trình đơn từ tệp tài nguyên map_options.
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
   val inflater = menuInflater
   inflater.inflate(R.menu.map_options, menu)
   return true
}
  1. Trong MapsActivity.kt, hãy ghi đè phương thức onOptionsItemSelected(). Thay đổi loại bản đồ bằng cách sử dụng các hằng số loại bản đồ để phản ánh lựa chọn của người dùng.
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
   // Change the map type based on the user's selection.
   R.id.normal_map -> {
       map.mapType = GoogleMap.MAP_TYPE_NORMAL
       true
   }
   R.id.hybrid_map -> {
       map.mapType = GoogleMap.MAP_TYPE_HYBRID
       true
   }
   R.id.satellite_map -> {
       map.mapType = GoogleMap.MAP_TYPE_SATELLITE
       true
   }
   R.id.terrain_map -> {
       map.mapType = GoogleMap.MAP_TYPE_TERRAIN
       true
   }
   else -> super.onOptionsItemSelected(item)
}
  1. Chạy ứng dụng.
  2. Nhấp vào biểu tượng để thay đổi loại bản đồ. Lưu ý cách giao diện của bản đồ thay đổi giữa các chế độ.

Theo mặc định, lệnh gọi lại onMapReady() bao gồm mã đặt một điểm đánh dấu ở Sydney, Úc, nơi Google Maps được tạo ra. Lệnh gọi lại mặc định cũng tạo hiệu ứng cho bản đồ để di chuyển đến Sydney.

Trong nhiệm vụ này, bạn sẽ di chuyển camera của bản đồ đến nhà riêng, phóng to đến cấp độ mà bạn chỉ định và đặt một điểm đánh dấu ở đó.

Bước 1: Phóng to nhà của bạn và thêm một điểm đánh dấu

  1. Trong tệp MapsActivity.kt, hãy tìm phương thức onMapReady(). Xoá mã trong đó đặt điểm đánh dấu ở Sydney và di chuyển camera. Phương thức của bạn hiện sẽ có dạng như sau.
override fun onMapReady(googleMap: GoogleMap) {
   map = googleMap

}
  1. Tìm vĩ độ và kinh độ của nhà riêng bằng cách làm theo hướng dẫn này.
  2. Tạo một giá trị cho vĩ độ và một giá trị cho kinh độ, rồi nhập các giá trị số thực của chúng.
val latitude = 37.422160
val longitude = -122.084270
  1. Tạo một đối tượng LatLng mới có tên là homeLatLng. Trong đối tượng homeLatLng, hãy truyền các giá trị bạn vừa tạo.
val homeLatLng = LatLng(latitude, longitude)
  1. Tạo val cho mức thu phóng mà bạn muốn trên bản đồ. Sử dụng mức thu phóng 15f.
val zoomLevel = 15f

Mức thu phóng kiểm soát mức độ phóng to của bạn trên bản đồ. Danh sách sau đây giúp bạn hình dung được mức độ chi tiết mà mỗi cấp độ thu phóng hiển thị:

  • 1: Thế giới
  • 5: Vùng đất/lục địa
  • 10: Thành phố
  • 15: Đường phố
  • 20: Toà nhà
  1. Di chuyển camera đến homeLatLng bằng cách gọi hàm moveCamera() trên đối tượng map và truyền vào một đối tượng CameraUpdate bằng cách sử dụng CameraUpdateFactory.newLatLngZoom(). Truyền vào đối tượng homeLatLngzoomLevel.
map.moveCamera(CameraUpdateFactory.newLatLngZoom(homeLatLng, zoomLevel))
  1. Thêm điểm đánh dấu vào bản đồ tại homeLatLng.
map.addMarker(MarkerOptions().position(homeLatLng))

Phương pháp cuối cùng của bạn sẽ có dạng như sau:

override fun onMapReady(googleMap: GoogleMap) {
   map = googleMap

   //These coordinates represent the latitude and longitude of the Googleplex.
   val latitude = 37.422160
   val longitude = -122.084270
   val zoomLevel = 15f

   val homeLatLng = LatLng(latitude, longitude)
   map.moveCamera(CameraUpdateFactory.newLatLngZoom(homeLatLng, zoomLevel))
   map.addMarker(MarkerOptions().position(homeLatLng))
}
  1. Chạy ứng dụng của bạn. Bản đồ sẽ chuyển đến vị trí nhà của bạn, phóng to đến mức mong muốn và đặt một điểm đánh dấu trên vị trí nhà của bạn.

Bước 2: Cho phép người dùng thêm điểm đánh dấu bằng cách nhấp và giữ

Ở bước này, bạn sẽ thêm một điểm đánh dấu khi người dùng chạm và giữ một vị trí trên bản đồ.

  1. Tạo một phương thức sơ khai trong MapsActivity có tên là setMapLongClick(). Phương thức này nhận GoogleMap làm đối số.
  2. Đính kèm trình nghe setOnMapLongClickListener vào đối tượng bản đồ.
private fun setMapLongClick(map:GoogleMap) {
   map.setOnMapLongClickListener { }
}
  1. Trong setOnMapLongClickListener(), hãy gọi phương thức addMarker(). Truyền vào một đối tượng MarkerOptions mới có vị trí được đặt thành LatLng đã truyền vào.
private fun setMapLongClick(map: GoogleMap) {
   map.setOnMapLongClickListener { latLng ->
       map.addMarker(
           MarkerOptions()
               .position(latLng)
       )
   }
}
  1. Ở cuối phương thức onMapReady(), hãy gọi setMapLongClick() bằng map.
override fun onMapReady(googleMap: GoogleMap) {
   ...
  
   setMapLongClick(map)
}
  1. Chạy ứng dụng của bạn.
  2. Chạm và giữ trên bản đồ để đặt điểm đánh dấu tại một vị trí.
  3. Nhấn vào điểm đánh dấu để đưa điểm đó vào giữa màn hình.

Bước 3: Thêm một cửa sổ thông tin cho điểm đánh dấu

Trong bước này, bạn sẽ thêm một InfoWindow hiển thị toạ độ của điểm đánh dấu khi người dùng nhấn vào điểm đánh dấu.

  1. Trong setMapLongClick()setOnMapLongClickListener(), hãy tạo một val cho snippet. Đoạn trích là văn bản bổ sung xuất hiện sau tiêu đề. Đoạn trích của bạn sẽ hiển thị vĩ độ và kinh độ của một điểm đánh dấu.
private fun setMapLongClick(map: GoogleMap) {
   map.setOnMapLongClickListener { latLng ->
       // A snippet is additional text that's displayed after the title.
       val snippet = String.format(
           Locale.getDefault(),
           "Lat: %1$.5f, Long: %2$.5f",
           latLng.latitude,
           latLng.longitude
       )
       map.addMarker(
           MarkerOptions()
               .position(latLng)
       )
   }
}
  1. Trong addMarker(), hãy đặt title của điểm đánh dấu thành Dropped Pin (Ghim đã thả) bằng cách sử dụng tài nguyên chuỗi R.string.dropped_pin.
  2. Đặt snippet của điểm đánh dấu thành snippet.

Hàm hoàn chỉnh sẽ có dạng như sau:

private fun setMapLongClick(map: GoogleMap) {
   map.setOnMapLongClickListener { latLng ->
       // A Snippet is Additional text that's displayed below the title.
       val snippet = String.format(
           Locale.getDefault(),
           "Lat: %1$.5f, Long: %2$.5f",
           latLng.latitude,
           latLng.longitude
       )
       map.addMarker(
           MarkerOptions()
               .position(latLng)
               .title(getString(R.string.dropped_pin))
               .snippet(snippet)
              
       )
   }
}
  1. Chạy ứng dụng của bạn.
  2. Chạm và giữ trên bản đồ để thả điểm đánh dấu vị trí.
  3. Nhấn vào điểm đánh dấu để hiện cửa sổ thông tin.

Bước 4: Thêm trình nghe POI

Theo mặc định, các địa điểm yêu thích (POI) sẽ xuất hiện trên bản đồ cùng với biểu tượng tương ứng. POI bao gồm công viên, trường học, toà nhà chính phủ và nhiều địa điểm khác. Khi bạn đặt loại bản đồ thành normal, các địa điểm yêu thích của doanh nghiệp cũng sẽ xuất hiện trên bản đồ. Địa điểm yêu thích của doanh nghiệp đại diện cho các doanh nghiệp, chẳng hạn như cửa hàng, nhà hàng và khách sạn.

Trong bước này, bạn sẽ thêm một GoogleMap.OnPoiClickListener vào bản đồ. Trình xử lý sự kiện nhấp này sẽ đặt một điểm đánh dấu trên bản đồ ngay khi người dùng nhấp vào một địa điểm yêu thích. Trình nghe lượt nhấp cũng hiển thị một cửa sổ thông tin chứa tên của địa điểm yêu thích.

  1. Tạo một phương thức sơ khai trong MapsActivity có tên là setPoiClick(). Phương thức này nhận GoogleMap làm đối số.
  2. Trong phương thức setPoiClick(), hãy đặt một OnPoiClickListener trên GoogleMap được truyền vào.
private fun setPoiClick(map: GoogleMap) {
   map.setOnPoiClickListener { poi ->

   }
}
  1. Trong setOnPoiClickListener(), hãy tạo một val poiMarker cho điểm đánh dấu .
  2. Đặt thành một điểm đánh dấu bằng cách sử dụng map.addMarker() với MarkerOptions đặt title thành tên của địa điểm yêu thích.
private fun setPoiClick(map: GoogleMap) {
   map.setOnPoiClickListener { poi ->
       val poiMarker = map.addMarker(
           MarkerOptions()
               .position(poi.latLng)
               .title(poi.name)
       )
   }
}
  1. Trong hàm setOnPoiClickListener(), hãy gọi showInfoWindow() trên poiMarker để hiện ngay cửa sổ thông tin.
poiMarker.showInfoWindow()

Đoạn mã cuối cùng cho hàm setPoiClick() sẽ có dạng như sau.

private fun setPoiClick(map: GoogleMap) {
   map.setOnPoiClickListener { poi ->
       val poiMarker = map.addMarker(
           MarkerOptions()
               .position(poi.latLng)
               .title(poi.name)
       )
       poiMarker.showInfoWindow()
   }
}
  1. Khi kết thúc onMapReady(), hãy gọi setPoiClick() và truyền vào map.
override fun onMapReady(googleMap: GoogleMap) {
   ...

   setPoiClick(map)
}
  1. Chạy ứng dụng của bạn và tìm một địa điểm yêu thích, chẳng hạn như công viên hoặc quán cà phê.
  2. Nhấn vào địa điểm yêu thích để đặt một điểm đánh dấu trên địa điểm đó và hiển thị tên của địa điểm yêu thích trong một cửa sổ thông tin.

Bạn có thể tuỳ chỉnh Google Maps theo nhiều cách để tạo cho bản đồ của mình một diện mạo độc đáo.

Bạn có thể tuỳ chỉnh đối tượng MapFragment bằng cách sử dụng các thuộc tính XML có sẵn, giống như cách bạn tuỳ chỉnh mọi mảnh khác. Tuy nhiên, ở bước này, bạn sẽ tuỳ chỉnh giao diện của nội dung của MapFragment bằng cách sử dụng các phương thức trên đối tượng GoogleMap.

Để tạo kiểu tuỳ chỉnh cho bản đồ, bạn tạo một tệp JSON chỉ định cách hiển thị các đối tượng trên bản đồ. Bạn không cần phải tạo tệp JSON này theo cách thủ công. Google cung cấp Trình hướng dẫn tạo kiểu cho Nền tảng Maps. Trình hướng dẫn này sẽ tạo JSON cho bạn sau khi bạn tạo kiểu trực quan cho bản đồ. Trong nhiệm vụ này, bạn sẽ tạo kiểu cho bản đồ bằng một giao diện cổ điển, tức là bản đồ sẽ sử dụng các màu sắc cổ điển và bạn sẽ thêm các con đường có màu.

Bước 1: Tạo kiểu cho bản đồ

  1. Truy cập vào https://mapstyle.withgoogle.com/ trong trình duyệt.
  2. Chọn Tạo kiểu.
  3. Chọn Retro.

  1. Nhấp vào Tùy chọn khác.

  1. Trong danh sách Loại đối tượng, hãy chọn Đường > Tô màu.
  2. Thay đổi màu của đường thành màu bất kỳ mà bạn chọn (chẳng hạn như màu hồng).

  1. Nhấp vào Hoàn tất.

  1. Sao chép mã JSON từ hộp thoại kết quả và nếu muốn, hãy lưu trữ mã đó trong một ghi chú văn bản thuần tuý để sử dụng trong bước tiếp theo.

Bước 2: Thêm kiểu vào bản đồ

  1. Trong Android Studio, trong thư mục res , hãy tạo một thư mục tài nguyên và đặt tên là raw. Bạn sử dụng các tài nguyên trong thư mục raw như mã JSON.
  2. Tạo một tệp trong res/raw có tên là map_style.json.
  3. Dán mã JSON bạn đã lưu trữ vào tệp tài nguyên mới.
  4. Trong MapsActivity, hãy tạo một biến lớp TAG phía trên phương thức onCreate(). Thông tin này được dùng cho mục đích ghi nhật ký.
private val TAG = MapsActivity::class.java.simpleName
  1. Cũng trong MapsActivity, hãy tạo một hàm setMapStyle() nhận một GoogleMap.
  2. Trong setMapStyle(), hãy thêm một khối try{}.
  3. Trong khối try{}, hãy tạo một val success để tạo kiểu thành công. (Bạn sẽ thêm khối catch sau đây.)
  4. Trong khối try{}, hãy đặt kiểu JSON cho bản đồ, gọi setMapStyle() trên đối tượng GoogleMap. Truyền vào một đối tượng MapStyleOptions, đối tượng này sẽ tải tệp JSON.
  5. Chỉ định kết quả cho success. Phương thức setMapStyle() trả về một giá trị boolean cho biết trạng thái thành công của việc phân tích cú pháp tệp tạo kiểu và thiết lập kiểu.
private fun setMapStyle(map: GoogleMap) {
   try {
       // Customize the styling of the base map using a JSON object defined
       // in a raw resource file.
       val success = map.setMapStyle(
           MapStyleOptions.loadRawResourceStyle(
               this,
               R.raw.map_style
           )
       )
   }
}
  1. Thêm một câu lệnh if cho success có giá trị false. Nếu không tạo kiểu được, hãy in một nhật ký cho biết quá trình phân tích cú pháp không thành công.
private fun setMapStyle(map: GoogleMap) {
   try {
       ...
       if (!success) {
           Log.e(TAG, "Style parsing failed.")
       }
   }
}
  1. Thêm một khối catch{} để xử lý trường hợp thiếu tệp kiểu. Trong khối catch, nếu không tải được tệp, hãy gửi một Resources.NotFoundException.
private fun setMapStyle(map: GoogleMap) {
   try {
       ...
   } catch (e: Resources.NotFoundException) {
       Log.e(TAG, "Can't find style. Error: ", e)
   }
}

Phương thức hoàn chỉnh sẽ có dạng như đoạn mã sau:

private fun setMapStyle(map: GoogleMap) {
   try {
       // Customize the styling of the base map using a JSON object defined
       // in a raw resource file.
       val success = map.setMapStyle(
           MapStyleOptions.loadRawResourceStyle(
               this,
               R.raw.map_style
           )
       )

       if (!success) {
           Log.e(TAG, "Style parsing failed.")
       }
   } catch (e: Resources.NotFoundException) {
       Log.e(TAG, "Can't find style. Error: ", e)
   }
}
  1. Cuối cùng, hãy gọi phương thức setMapStyle() trong phương thức onMapReady() bằng cách truyền vào đối tượng GoogleMap.
override fun onMapReady(googleMap: GoogleMap) {
   ...
   setMapStyle(map)
}
  1. Chạy ứng dụng của bạn.
  2. Đặt bản đồ ở chế độ normal. Lúc này, bạn sẽ thấy kiểu mới với chủ đề cổ điển và đường có màu bạn chọn.

Bước 3: Tạo kiểu cho điểm đánh dấu

Bạn có thể cá nhân hoá bản đồ hơn nữa bằng cách tạo kiểu cho các điểm đánh dấu trên bản đồ. Trong bước này, bạn sẽ thay đổi các điểm đánh dấu màu đỏ mặc định thành một thứ gì đó thú vị hơn.

  1. Trong phương thức onMapLongClick(), hãy thêm dòng mã sau vào MarkerOptions() của hàm khởi tạo để sử dụng điểm đánh dấu mặc định, nhưng thay đổi màu thành xanh dương.
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE))

onMapLongClickListener() hiện sẽ có dạng như sau:

map.setOnMapLongClickListener { latLng ->
   // A snippet is additional text that's displayed after the title.
   val snippet = String.format(
       Locale.getDefault(),
       "Lat: %1$.5f, Long: %2$.5f",
       latLng.latitude,
       latLng.longitude
   )
   map.addMarker(
       MarkerOptions()
           .position(latLng)
           .title(getString(R.string.dropped_pin))
           .snippet(snippet)
         .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE))
   )
}
  1. Chạy ứng dụng. Các điểm đánh dấu xuất hiện sau khi bạn nhấp và giữ hiện có màu xanh dương. Xin lưu ý rằng các điểm đánh dấu địa điểm yêu thích vẫn có màu đỏ vì bạn chưa thêm kiểu cho phương thức onPoiClick().

Một cách để tuỳ chỉnh bản đồ trên Google là vẽ lên trên bản đồ. Kỹ thuật này hữu ích nếu bạn muốn làm nổi bật một loại vị trí cụ thể, chẳng hạn như các điểm câu cá nổi tiếng.

  • Hình dạng: Bạn có thể thêm đường nhiều đoạn, đa giácvòng tròn vào bản đồ.
  • GroundOverlay đối tượng: Lớp phủ trên mặt đất là một hình ảnh được cố định vào bản đồ. Không giống như điểm đánh dấu, lớp phủ mặt đất được định hướng theo bề mặt Trái Đất chứ không phải theo màn hình. Việc xoay, nghiêng hoặc thu phóng bản đồ sẽ thay đổi hướng của hình ảnh. Lớp phủ mặt đất rất hữu ích khi bạn muốn cố định một hình ảnh tại một khu vực trên bản đồ.

Bước: Thêm lớp phủ mặt đất

Trong nhiệm vụ này, bạn sẽ thêm một lớp phủ mặt đất có hình dạng của Android vào vị trí nhà riêng.

  1. Tải hình ảnh Android này xuống rồi lưu vào thư mục res/drawable. (Đảm bảo tên tệp là android.png.)

  1. Trong onMapReady(), sau khi gọi để di chuyển camera đến vị trí nhà bạn, hãy tạo một đối tượng GroundOverlayOptions.
  2. Chỉ định đối tượng cho một biến có tên là androidOverlay.
val androidOverlay = GroundOverlayOptions()
  1. Sử dụng phương thức BitmapDescriptorFactory.fromResource() để tạo một đối tượng BitmapDescriptor từ tài nguyên hình ảnh đã tải xuống.
  2. Truyền đối tượng BitmapDescriptor thu được vào phương thức image() của đối tượng GroundOverlayOptions.
val androidOverlay = GroundOverlayOptions()
   .image(BitmapDescriptorFactory.fromResource(R.drawable.android))
  1. Tạo một float overlaySize cho chiều rộng tính bằng mét của lớp phủ mong muốn. Trong ví dụ này, chiều rộng 100f sẽ phù hợp.

Đặt thuộc tính position cho đối tượng GroundOverlayOptions bằng cách gọi phương thức position(), đồng thời truyền đối tượng homeLatLngoverlaySize vào.

val overlaySize = 100f
val androidOverlay = GroundOverlayOptions()
   .image(BitmapDescriptorFactory.fromResource(R.drawable.android))
   .position(homeLatLng, overlaySize)
  1. Gọi addGroundOverlay() trên đối tượng GoogleMap và truyền vào đối tượng GroundOverlayOptions.
map.addGroundOverlay(androidOverlay)
  1. Chạy ứng dụng.
  2. Thay đổi giá trị của zoomLevel thành 18f để xem hình ảnh Android dưới dạng lớp phủ.

Người dùng thường sử dụng Google Maps để xem vị trí hiện tại của họ. Để hiển thị vị trí của thiết bị trên bản đồ, bạn có thể sử dụng lớp dữ liệu vị trí.

Lớp dữ liệu vị trí sẽ thêm Vị trí của tôi vào bản đồ. Khi người dùng nhấn vào nút này, bản đồ sẽ tập trung vào vị trí của thiết bị. Vị trí sẽ xuất hiện dưới dạng một chấm màu xanh dương nếu thiết bị đang đứng yên và dưới dạng một dấu nhọn màu xanh dương nếu thiết bị đang di chuyển.

Trong nhiệm vụ này, bạn sẽ bật lớp dữ liệu vị trí.

Bước: Yêu cầu cấp quyền truy cập thông tin vị trí

Bạn chỉ cần một dòng mã để bật tính năng theo dõi vị trí trong Google Maps. Tuy nhiên, bạn phải đảm bảo rằng người dùng đã cấp quyền truy cập vào vị trí (bằng cách sử dụng mô hình quyền khi bắt đầu chạy).

Trong bước này, bạn yêu cầu cấp quyền truy cập thông tin vị trí và bật tính năng theo dõi vị trí.

  1. Trong tệp AndroidManifest.xml, hãy xác minh rằng quyền FINE_LOCATION đã có sẵn. Android Studio đã chèn quyền này khi bạn chọn mẫu Google Maps.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  1. Trong MapsActivity, hãy tạo một biến lớp REQUEST_LOCATION_PERMISSION.
private val REQUEST_LOCATION_PERMISSION = 1
  1. Để kiểm tra xem các quyền đã được cấp hay chưa, hãy tạo một phương thức trong MapsActivity có tên là isPermissionGranted(). Trong phương thức này, hãy kiểm tra xem người dùng đã cấp quyền hay chưa.
private fun isPermissionGranted() : Boolean {
  return ContextCompat.checkSelfPermission(
       this,
      Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
}
  1. Để bật tính năng theo dõi vị trí trong ứng dụng, hãy tạo một phương thức trong MapsActivity có tên là enableMyLocation(). Phương thức này không nhận đối số và không trả về giá trị nào. Trong đó, hãy kiểm tra quyền ACCESS_FINE_LOCATION. Nếu được cấp quyền, hãy bật lớp vị trí. Trường hợp còn lại, đoạn mã sẽ yêu cầu được cấp quyền đó.
private fun enableMyLocation() {
   if (isPermissionGranted()) {
       map.isMyLocationEnabled = true 
   }
   else {
       ActivityCompat.requestPermissions(
           this,
           arrayOf<String>(Manifest.permission.ACCESS_FINE_LOCATION),
           REQUEST_LOCATION_PERMISSION
       )
   }
}
  1. Gọi enableMyLocation() từ lệnh gọi lại onMapReady() để bật lớp vị trí.
override fun onMapReady(googleMap: GoogleMap) {
   ...
   enableMyLocation()
}
  1. Ghi đè phương thức onRequestPermissionsResult(). Nếu requestCode bằng REQUEST_LOCATION_PERMISSION, tức là quyền đã được cấp. Nếu mảng grantResults không trống và có PackageManager.PERMISSION_GRANTED ở vị trí đầu tiên, hãy gọi enableMyLocation().
override fun onRequestPermissionsResult(
   requestCode: Int,
   permissions: Array<String>,
   grantResults: IntArray) {
   if (requestCode == REQUEST_LOCATION_PERMISSION) {
       if (grantResults.contains(PackageManager.PERMISSION_GRANTED)) {
           enableMyLocation()
       }
   }
}
  1. Chạy ứng dụng của bạn. Sẽ có một hộp thoại yêu cầu quyền truy cập vào thông tin vị trí của thiết bị. Tiếp tục và cấp quyền.

Bây giờ, bản đồ sẽ hiển thị vị trí hiện tại của thiết bị bằng một chấm màu xanh dương. Lưu ý rằng có một nút vị trí. Nếu bạn di chuyển bản đồ ra khỏi vị trí của mình và nhấp vào nút này, bản đồ sẽ quay về vị trí của thiết bị.

Tải mã xuống cho lớp học lập trình đã hoàn thành.

$  git clone https://github.com/googlecodelabs/android-kotlin-geo-maps


Ngoài ra, bạn có thể tải kho lưu trữ xuống dưới dạng tệp zip, giải nén và mở tệp đó trong Android Studio.

Tải tệp ZIP xuống

  • Để sử dụng Maps API, bạn cần có một khoá API từ Google API Console.
  • Trong Android Studio, việc sử dụng mẫu Google Maps Activity sẽ tạo ra một Activity có một SupportMapFragment duy nhất trong bố cục của ứng dụng. Mẫu này cũng thêm ACCESS_FINE_PERMISSION vào tệp kê khai ứng dụng, đồng thời triển khai OnMapReadyCallback trong hoạt động của bạn và ghi đè phương thức onMapReady() bắt buộc.

Để thay đổi loại bản đồ của một GoogleMap trong thời gian chạy, hãy sử dụng phương thức GoogleMap.setMapType(). Google Maps có thể là một trong những loại bản đồ sau:

  • Bình thường: Bản đồ đường bộ thông thường. Cho thấy đường, một số công trình do con người xây dựng và các đặc điểm tự nhiên quan trọng như sông. Nhãn đường và nhãn đối tượng cũng xuất hiện.
  • Kết hợp: Dữ liệu ảnh vệ tinh có thêm bản đồ đường. Nhãn đường và nhãn đối tượng cũng xuất hiện.
  • Vệ tinh: Dữ liệu ảnh. Nhãn đường và đối tượng không xuất hiện.
  • Địa hình: Dữ liệu địa hình. Bản đồ có màu sắc, đường viền và nhãn, cũng như hiệu ứng đổ bóng phối cảnh. Một số đường và nhãn cũng xuất hiện.
  • None: Không có ô bản đồ cơ sở.

Giới thiệu về Google Maps:

  • Điểm đánh dấu là một chỉ báo cho một vị trí địa lý cụ thể.
  • Khi được nhấn, hành vi mặc định của điểm đánh dấu là hiển thị một cửa sổ thông tin có thông tin về vị trí.
  • Theo mặc định, các địa điểm yêu thích (POI) sẽ xuất hiện trên bản đồ cơ sở cùng với các biểu tượng tương ứng. POI bao gồm công viên, trường học, toà nhà chính phủ và nhiều địa điểm khác.
  • Ngoài ra, các địa điểm yêu thích của doanh nghiệp (cửa hàng, nhà hàng, khách sạn và nhiều địa điểm khác) sẽ xuất hiện theo mặc định trên bản đồ khi loại bản đồ là normal.
  • Bạn có thể ghi lại các lượt nhấp vào các địa điểm yêu thích bằng cách sử dụng OnPoiClickListener.
  • Bạn có thể thay đổi giao diện trực quan của hầu hết mọi phần tử trên Google Maps bằng cách sử dụng Trình hướng dẫn tạo kiểu. Trình hướng dẫn tạo kiểu sẽ tạo một tệp JSON mà bạn truyền vào Google Maps bằng phương thức setMapStyle().
  • Bạn có thể tuỳ chỉnh điểm đánh dấu bằng cách thay đổi màu mặc định hoặc thay thế biểu tượng điểm đánh dấu mặc định bằng một hình ảnh tuỳ chỉnh.

Các thông tin quan trọng khác:

  • Sử dụng lớp phủ mặt đất để cố định hình ảnh vào một vị trí địa lý.
  • Sử dụng đối tượng GroundOverlayOptions để chỉ định hình ảnh, kích thước của hình ảnh tính bằng mét và vị trí của hình ảnh. Truyền đối tượng này vào phương thức GoogleMap.addGroundOverlay() để đặt lớp phủ cho bản đồ.
  • Miễn là ứng dụng của bạn có quyền ACCESS_FINE_LOCATION, bạn có thể bật tính năng theo dõi vị trí bằng cách đặt map.isMyLocationEnabled = true.
  • Lớp học lập trình này không đề cập đến vấn đề này, nhưng bạn có thể cung cấp thêm thông tin về một vị trí bằng Chế độ xem đường phố của Google. Đây là ảnh toàn cảnh có thể điều hướng của một vị trí nhất định.

Tài liệu dành cho nhà phát triển Android:

Tài liệu tham khảo:

Để biết đường liên kết đến các lớp học lập trình khác trong khoá học này, hãy xem trang đích của các lớp học lập trình trong khoá học Kiến thức nâng cao về cách tạo ứng dụng Android bằng Kotlin.