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

1. Trước khi bắt đầu

Tạo ứng dụng bằng Google Maps cho phép bạn thêm 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 tùy chọn kiểm soát mạnh mẽ trên giao diện người dùng dành cho bản đồ, theo dõi vị trí và các điểm đánh dấu vị trí. Bạn có thể thêm 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 trò chơi trong đó người chơi khám phá thế giới thực, chẳng hạn như trong cuộc 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

Kiến thức về:

  • Nắm được cách tạo và chạy ứng dụng Android cơ bản 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 đồ 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ủa bạn
  • Cách hiển thị các loại bản đồ khác nhau
  • Cách tạo kiểu cho Google Maps
  • Cách thêm điểm đánh dấu vào bản đồ của bạn
  • Cách cho phép người dùng đặt điểm đánh dấu vào đị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, trong đó có một Google Maps được nhúng
  • Cách tạo tính năng tuỳ chỉnh cho ứng dụng, chẳng hạn như điểm đánh dấu và định kiểu
  • Cách bật tính năng theo dõi vị trí trong ứng dụng của bạn

2. Tổng quan về ứ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ị bản đồ Google với kiểu tuỳ chỉnh. Ứng dụng Wander cho phép bạn thả điểm đánh dấu vào vị trí, thêm lớp phủ và xem vị trí của bạn theo thời gian thực.

5b12eda7f467bc2f.png.

3. Nhiệm vụ: Thiết lập dự án và tải Khoá API

SDK bản đồ dành cho Android yêu cầu khoá API. Để có được khoá API, hãy đăng ký dự án của bạn trong API & Dịch vụ. Khoá API được gắn với một chứng chỉ kỹ thuật số liên kết ứng dụng với tác giả của khoá đó. Để 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. Chứng chỉ gỡ lỗi không an toàn theo thiết kế, như mô tả trong bài viết Ký bản gỡ lỗi. Các ứng dụng Android đã phát hành có sử dụng Maps SDK dành cho Android yêu cầu 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 chứa một mẫu Hoạt động trên Google Maps để tạo mã mẫu hữu ích. Mã mẫu bao gồm tệp google_maps_api.xml chứa đườ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.

d6b874bb19ea68cd.png

  1. Đặt tên cho dự án là 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 tạo xong ứng dụng, 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 sử dụng tệp cấu hình này để lưu khoá API. Mẫu này tạo 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 cho khoá API cho chứng chỉ gỡ lỗi nằm trong src/debug/res/values. Tệp cho khoá API cho 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 ứng dụng. Đó là một trình bao bọc xung quanh chế độ xem 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ể đưa SupportMapFragment vào tệp bố cục bằng thẻ <fragment> trong bất kỳ ViewGroup nào, kèm theo thuộc tính name bổ sung.

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

MapsActivity.java – Tệp MapsActivity.java tạo thực thể của SupportMapFragment trong phương thức onCreate() và sử dụng lớp này getMapAsync() để tự động khởi chạy hệ thống bản đồ và chế độ xem. 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 nhận xét 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 các API và Dịch vụ. Do các tham số trong URL được cung cấp, trang biết để tự động bật SDK bản đồ cho Android.
  5. Nhấp vào Tạo khoá API.
  6. Trên trang tiếp theo, chuyển đến phần Khoá API rồi nhấp vào khoá bạn vừa tạo.
  7. Nhấp vào Hạn chế khoá rồi chọn SDK Maps 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. Mã này sẽ bắt đầu bằng "AIza".
  9. Trong tệp google_maps_api.xml, hãy dán khoá vào chuỗi google_maps_key cho biết YOUR_KEY_HERE.
  10. Chạy ứng dụng. Bạn sẽ nhìn thấy một bản đồ được nhúng trong hoạt động của mình cùng với một điểm đánh dấu được thiết lập ở Sydney, Úc. (Điểm đánh dấu Sydney là một phần của mẫu và bạn sẽ thay đổi nó sau.)

34dc9dd877c90996.pngS

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

MapsActivity có một lateinit var riêng tư tên là mMap thuộc kiểu GoogleMap. Để tuân theo quy ước đặt tên của Kotlin, hãy đổi tên của 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) > Đổi tên...

e713ccb3384450c6.png

  1. Hãy thay đổi tên biến thành map.

Hãy lưu ý cách mọi tham chiếu đến mMap trong hàm onMapReady() cũng thay đổi thành map.

4. Nhiệm vụ: Thêm loại bản đồ

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

Bản đồ thông thường

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 nhìn thấy tên đường phố, vì vậy, bạn có thể sử dụng lựa chọn thông thường. Khi bạn đi bộ đường dài, bản đồ địa hình có thể hữu ích trong việc quyết định bạn phải leo thêm bao nhiêu nữa để lên đến đỉnh.

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

  1. Thêm 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 hỗ trợ cho các điểm đánh dấu, cho biết các vị trí đơn lẻ trên bản đồ và có thể bao gồm nhãn.

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

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

  1. Để tạo 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 Mới > Tệp tài nguyên Android.
  2. Trong hộp thoại, hãy đặt tên cho 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 mã sau để tạo các lựa chọn trên trình đơn bản đồ. Giá trị "không" loại bản đồ bị bỏ qua vì "không có" dẫn đến việc thiếu bản đồ. Bước này gây ra lỗi nhưng bạn sẽ giải quyết được lỗi này 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 để sửa 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 hằng số loại ánh xạ để 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 428da163b831115b.png. để thay đổi loại bản đồ. Hãy chú ý cách giao diện của bản đồ thay đổi giữa các chế độ.

6fa42970d87f5dc7.png.

5. Nhiệm vụ: Thêm điểm đánh dấu

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. Lệnh gọi lại mặc định cũng tạo ảnh động cho bản đồ để xoay sang Sydney.

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

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

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

}
  1. Tìm vĩ độ và kinh độ của nhà bạn bằng cách làm theo các hướng dẫn này.
  2. Tạo một giá trị cho vĩ độ và một giá trị cho kinh độ, đồng thời nhập 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 vào.
val homeLatLng = LatLng(latitude, longitude)
  1. Tạo val để thể hiện mức độ phóng to 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 độ bạn được phóng to trên bản đồ. Danh sách sau đây cho bạn biết mức độ chi tiết mà mỗi mức 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 rồi truyền vào đố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 một đ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. Bản đồ sẽ xoay tới nhà bạn, phóng to đến mức mong muốn và đặt một điểm đánh dấu trên nhà của bạn.

fc939024778ee76.png

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ữ

Trong bước này, bạn 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 mã giả lập phương thức trong MapsActivity có tên là setMapLongClick(). Mã này sẽ lấy GoogleMap làm đối số.
  2. Đính kèm trình nghe setOnMapLongClickListener vào đối tượng ánh xạ.
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ữ bản đồ để đặt điểm đánh dấu tại một vị trí.
  3. Nhấn vào điểm đánh dấu để đặt điểm đánh dấu vào giữa màn hình.

4ff8d1c1db3bca9e.pngS

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

Ở bước này, bạn sẽ thêm một InfoWindow cho thấy toạ độ của điểm đánh dấu khi điểm đánh dấu được nhấn vào.

  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 mã của bạn hiển thị vĩ độ và kinh độ của đ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 Ghim đã thả bằ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ữ bản đồ để thả một điểm đánh dấu vị trí.
  3. Nhấn vào điểm đánh dấu để hiển thị cửa sổ thông tin.

63f210e6e47dfa29.png.

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 các biểu tượng tương ứng của chúng. Địa điểm yêu thích bao gồm công viên, trường học, toà nhà chính phủ và các đị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 là 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.

Ở bước này, bạn thêm một GoogleMap.OnPoiClickListener vào bản đồ. Trình nghe lượt nhấp này đặ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ị cửa sổ thông tin có chứa tên POI.

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

   }
}
  1. Trong setOnPoiClickListener(), tạo 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 thị cửa sổ thông tin ngay lập tức.
poiMarker.showInfoWindow()

Mã hoàn thiện 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. Ở cuối 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 và tìm đị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 lên địa điểm đó và hiển thị tên của địa điểm yêu thích đó trong cửa sổ thông tin.

f4b0972c75d5fa5f.png

6. Nhiệm vụ: Tạo kiểu cho bản đồ của bạn

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

Bạn có thể tuỳ chỉnh đối tượng MapFragment bằng các thuộc tính XML có sẵn, giống như cách bạn tuỳ chỉnh bất kỳ mảnh nào khác. Tuy nhiên, trong bước này, bạn tuỳ chỉnh giao diện 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 tùy chỉnh cho bản đồ của bạn, bạn tạo tệp JSON chỉ rõ cách hiển thị các đối tượng trong 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 trên 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 đồ của mình. Trong nhiệm vụ này, bạn tạo kiểu cho bản đồ bằng chủ đề hoài cổ, nghĩa là bản đồ sử dụng các màu cổ điển và thêm những con đường được tô màu.

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

  1. Hãy truy cập vào https://mapstyle.withgoogle.com/ trong trình duyệt của bạn.
  2. Chọn Tạo kiểu.
  3. Chọn .

208b3d3aeab0d9b6.pngS

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

4a35faaf9535ee82.pngs

  1. Chọn Đường > Điền.
  2. Thay đổi màu đường thành bất kỳ màu nào bạn chọn (chẳng hạn như màu hồng).

92c3293749293a4c.png.

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

f1bfe8585eb69480.png

  1. Sao chép mã JSON từ hộp thoại hiện ra 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.

3c32168b299d6420.pngS

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

  1. Trong Android Studio, ở thư mục res, hãy tạo một thư mục tài nguyên rồi đặt tên cho thư mục đó là raw. Bạn sử dụng các tài nguyên 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 đã 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(). Dữ liệu này dùng cho mục đích ghi nhật ký.
private val TAG = MapsActivity::class.java.simpleName
  1. Ngoài ra, trong MapsActivity, hãy tạo một hàm setMapStyle() chứa 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 để có thể định kiểu thành công. (Bạn thêm khối tiêu đề sau.)
  4. Trong khối try{}, hãy thiết lập kiểu JSON thành 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 định kiểu và đặt 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 câu lệnh if cho success là false. Nếu việc định kiểu không thành công, hãy xuấ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 khối catch{} để xử lý trường hợp thiếu tệp kiểu. Trong khối catch, nếu không thể tải 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() 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 và kiểu mới sẽ hiển thị với giao diện và đường màu cổ điển mà bạn đã chọn.

b59d6cb81f02a14f.png

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

Bạn có thể cá nhân hoá bản đồ của mình hơn nữa bằng cách tạo kiểu cho điểm đánh dấu bản đồ. Trong bước này, bạn thay đổi điểm đánh dấu màu đỏ mặc định thành điểm đánh dấu hấp dẫn 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 màu 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. Điểm đánh dấu xuất hiện sau khi bạn nhấp và giữ giờ đây sẽ được tô màu xanh dương. Lưu ý rằng các điểm đánh dấu POI vẫn có màu đỏ vì bạn không thêm kiểu vào phương thức onPoiClick().

b9916bca3c367e3.png

7. Nhiệm vụ: Thêm lớp phủ

Bạn có thể tuỳ chỉnh bản đồ Google bằng cách vẽ lên trên bản đồ đó. Kỹ thuật này rất hữu ích nếu bạn muốn làm nổi bật một loại địa điểm 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 hình nhiều đường, đa giáchình tròn vào bản đồ.
  • GroundOverlay đối tượng: Lớp phủ mặt đất là hình ảnh được cố định với bản đồ. Không giống như điểm đánh dấu, lớp phủ mặt đất được định hướng về bề mặt Trái đất chứ không phải màn hình. 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 hữu ích khi bạn muốn sửa một hình ảnh trong 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 theo hình dạng Android vào vị trí nhà riêng của mình.

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

61fabd56a0841b44.png.

  1. Trong onMapReady(), sau lệnh 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 biến có tên là androidOverlay.
val androidOverlay = GroundOverlayOptions()
  1. Sử dụng phương thức BitmapDescriptorFactory.fromResource() để tạo đố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 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 của 100f là 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() rồi truyền vào đối tượng homeLatLngoverlaySize.

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 rồi 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ủ.

b1b25b0acd6a9807.png

8. Nhiệm vụ: Bật tính năng theo dõi vị trí

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í thêm biểu tượng Vị trí của tôi vào bản đồ.

f317f84dcb3ac3a1.png

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í được hiển thị dưới dạng chấm màu xanh dương nếu thiết bị đang cố định và dưới dạng vạch chữ v 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 quyền truy cập thông tin vị trí

Việc bật tính năng theo dõi vị trí trong Google Maps yêu cầu một dòng mã duy nhất. Tuy nhiên, bạn phải đảm bảo rằng người dùng đã cấp quyền truy cập thông tin vị trí (bằng mô hình quản lý quyền khi bắt đầu chạy).

Ở bước này, bạn yêu cầu 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ó. 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. Bên trong, hãy kiểm tra quyền ACCESS_FINE_LOCATION. Nếu quyền được cấp, hãy bật lớp vị trí. Nếu không, hãy yêu cầu 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(). Kiểm tra xem requestCode có bằng REQUEST_LOCATION_PERMISSION hay không. Nếu được cấp quyền thì điều đó có nghĩa là quyền đã được cấp. Nếu được cấp quyền, hãy kiểm tra xem mảng grantResults có chứa PackageManager.PERMISSION_GRANTED trong ô đầu tiên hay không. Nếu đúng như vậy, 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. Sẽ có một hộp thoại yêu cầu quyền truy cập vào vị trí của thiết bị. Hãy tiếp tục và cấp quyền.

da7e23e00ec762c1.png

Bản đồ giờ đây 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ó nút vị trí. Nếu bạn di chuyển bản đồ ra xa vị trí của mình và nhấp vào nút này, nút này sẽ căn giữa bản đồ trở về vị trí của thiết bị.

5b12eda7f467bc2f.png.

9. Đoạn mã giải pháp

Tải mã nguồn xuống khi lớp học lập trình đã kết thúc.

$  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, sau đó giải nén và mở trong Android Studio.

10. Tóm tắt

Xin chúc mừng! Bạn đã thêm một bản đồ Google vào một ứng dụng Android trên Kotlin và tạo kiểu cho nó.

11. Tìm hiểu thêm

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

Tài liệu tham khảo:

12. Lớp học lập trình tiếp theo

Để xem đườ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 lớp học lập trình Android bằng Kotlin nâng cao.