Android מתקדם בקוטלין 04.1: מפות Google ל-Android

מעבדת קוד זו היא חלק מהקורס המתקדם של Android בקורס Kotlin. כדי להפיק את המקסימום מהקורס הזה, אם עובדים על מעבדות הקוד ברצף, לא חובה לעשות זאת. כל שיעורי הקוד של הקורסים מופיעים בדף הנחיתה המתקדם של Android ב-Kotlin codelabs.

יצירת אפליקציות באמצעות מפות Google מאפשרת לכם להוסיף תכונות לאפליקציה, כמו תמונות לוויין, פקדי ממשק משתמש חזקים למפות Google, מעקב אחר מיקום וסמני מיקום. ניתן להוסיף ערך למפות Google הרגילות על ידי הצגת מידע ממערך הנתונים שלכם, כמו מיקומים של אזורי דיג או טיפוס ידועים. יש גם אפשרות ליצור משחקים שבהם השחקן מגלה את העולם הפיזי, למשל חיפוש אחר אוצרות או משחקים של מציאות רבודה.

בשיעור הזה אתם יוצרים אפליקציה של מפות Google בשם Wander, שמציגה מפות מותאמות אישית ומציגה את המיקום של המשתמש.

דרישות מוקדמות

הידע הזה:

  • איך ליצור אפליקציה בסיסית ל-Android ולהפעיל אותה באמצעות Android Studio.
  • איך יוצרים ומנהלים משאבים כמו מחרוזות?
  • איך להגדיר מחדש את הקוד ולשנות את השם של משתנים באמצעות Android Studio.
  • איך להשתמש במפה של Google כמשתמש.
  • איך להגדיר הרשאות בזמן ריצה.

מה תלמדו

  • איך מקבלים מפתח API מ-Google API Console ורושמים את המפתח לאפליקציה
  • איך לשלב את 'מפות Google' באפליקציה
  • איך להציג סוגי מפות שונים
  • איך לעצב את המפה של Google
  • איך להוסיף סמנים למפה
  • איך מאפשרים למשתמש להציב סמן בנקודת עניין (POI)
  • איך מפעילים מעקב אחר מיקום?
  • איך ליצור את האפליקציה Wander, שכוללת מפת Google מוטמעת
  • איך ליצור תכונות מותאמות אישית לאפליקציה, כמו סמנים וסגנון
  • איך להפעיל מעקב אחר מיקום באפליקציה

ב-lab זה אתם יוצרים את האפליקציה Wander, המציגה מפת Google עם סגנון מותאם אישית. אפליקציית וונדר מאפשרת לך להציב סמנים במיקומים שונים, להוסיף שכבות-על ולראות את המיקום שלך בזמן אמת.

ל-SDK של מפות Google ל-Android נדרש מפתח API. כדי לקבל את מפתח ה-API, רושמים את הפרויקט בדף API & שירותים. מפתח ה-API מקושר לאישור דיגיטלי המקשר את האפליקציה אל המחבר שלו. למידע נוסף על השימוש באישורים דיגיטליים ועל חתימת האפליקציה, יש לעיין במאמר חתימת האפליקציה שלך.

ב-codelab זה אתם משתמשים במפתח ה-API לאישור ניפוי הבאגים. אישור ניפוי הבאגים לא מאובטח בעיצוב, כפי שמתואר בחתימה על גרסת ה-build של ניפוי באגים. לאפליקציות Android שפורסמו שמשתמשות ב-Maps SDK ל-Android נדרש מפתח API שני: המפתח של אישור הגרסה. מידע נוסף על קבלת אישור גרסה זמין במאמר קבלת מפתח API.

Android Studio כולל תבנית פעילות של מפות Google, שיוצרת קוד תבנית מועיל. קוד התבנית כולל קובץ מסוג google_maps_api.xml שמכיל קישור שמפשט את קבלת מפתח API.

שלב 1: יצירת פרויקט Wander באמצעות התבנית של מפות Google

  1. יוצרים פרויקט חדש ב-Android Studio.
  2. בוחרים בתבנית פעילות במפות Google.

  1. נותנים שם לפרויקט Wander.
  2. מגדירים את רמת ה-API המינימלית ל-API 19. מוודאים שהשפה היא Kotlin.
  3. לוחצים על סיום.
  4. לאחר סיום הבנייה של האפליקציה, כדאי לבדוק את הפרויקט שלכם ואת הקבצים הבאים של מפות Google שמערכת Android Studio יוצרת עבורכם:

google_maps_api.xml — קובץ התצורה הזה משמש אתכם כדי לשמור את מפתח ה-API. התבנית יוצרת שני קובצי google_maps_api.xml: אחד לניפוי באגים וקובץ אחד לגרסה. הקובץ של מפתח ה-API של אישור ניפוי הבאגים נמצא ב-src/debug/res/values. הקובץ של מפתח ה-API של אישור הגרסה נמצא ב-src/release/res/values. ב-codelab זה תשתמשו רק באישור ניפוי הבאגים.

activity_maps.xml – קובץ הפריסה הזה מכיל שבר יחיד שממלא את כל המסך. הכיתה SupportMapFragment היא סיווג משנה של הכיתה Fragment. SupportMapFragment הוא הדרך הפשוטה ביותר למקם מפה באפליקציה. זוהי עיטוף מסביב לתצוגה של מפה שעונה על צורכי מחזור החיים הנדרשים באופן אוטומטי.

אפשר לכלול את SupportMapFragment בקובץ פריסה באמצעות תג <fragment> בכל ViewGroup, עם מאפיין name נוסף.

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

MapsActivity.JavaScript – הקובץ MapsActivity.kt יוצר את SupportMapFragment בשיטה onCreate() ומשתמש במחלקה&339. getMapAsync() כדי לאתחל באופן אוטומטי את מערכת המפות ואת התצוגה. הפעילות שמכילה את SupportMapFragment חייבת להטמיע את הממשק OnMapReadyCallback ואת שיטת onMapReady()הממשק הזה. מתבצעת קריאה לשיטת onMapReady() כאשר המפה נטענת.

שלב 2: קבלת מפתח API

  1. פותחים את גרסת ניפוי הבאגים של הקובץ google_maps_api.xml.
  2. בקובץ, מחפשים הערה עם כתובת URL ארוכה. הפרמטרים של כתובת האתר כוללים מידע ספציפי על האפליקציה שלך.
  3. מעתיקים את כתובת ה-URL ומדביקים אותה בדפדפן.
  4. מבצעים את ההנחיות ליצירת פרויקט בדף ממשקי ה-API ושירותי AMP. בשל הפרמטרים בכתובת ה-URL שצוינה, הדף יודע להפעיל את ה-SDK של מפות Google ל-Android באופן אוטומטי.
  5. לוחצים על יצירת מפתח API.
  6. בדף הבא, עוברים לקטע 'מפתחות API' ולוחצים על המפתח שיצרתם.
  7. לוחצים על הגבלת מקש ובוחרים באפשרות SDK של מפות Google ל-Android כדי להגביל את השימוש במפתח למפתח לאפליקציות ל-Android.
  8. מעתיקים את מפתח ה-API שנוצר. הוא מתחיל ב-"AIza".
  9. בקובץ google_maps_api.xml, מדביקים את המפתח במחרוזת google_maps_key במקום שבו כתוב YOUR_KEY_HERE.
  10. מריצים את האפליקציה. אמורה להופיע מפה מוטמעת בפעילות שלכם עם סמן שמוגדר בסידני, אוסטרליה. (הסמן בסידני הוא חלק מהתבנית ומשנים אותו מאוחר יותר).

שלב 3: שינוי שם המפה

לMapsActivity יש lateinit var פרטי בשם mMap, מסוג GoogleMap. כדי לפעול בהתאם למוסכמות של Cotlin למתן שמות, יש לשנות את השם של mMap ל-map.

  1. ב-MapsActivity, לוחצים לחיצה ימנית על mMap ואז לוחצים על Refactor > שינוי שם...

  1. משנים את השם של המשתנה לשם map.

שימו לב איך כל ההפניות ל-mMap בפונקציה onMapReady() משתנות גם ל-map.

במפות Google יש כמה סוגי מפות: רגיל, היברידי, לוויין, פני שטח ו-"ללא" (ללא מפה כלל).

מפה רגילה

מפת לוויין

מפה היברידית

מפת פני השטח

כל סוג של מפה מספק מידע מסוגים שונים. לדוגמה, בעת שימוש במפות לניווט במכונית, מומלץ לראות את שמות הרחובות כדי להשתמש באפשרות הרגילה. כשאתם מטיילים, מפת פני השטח יכולה לעזור לכם להחליט כמה טיפוס אתם צריכים כדי להגיע לפסגה.

במשימה הזו:

  1. יש להוסיף סרגל אפליקציות עם תפריט אפשרויות שמאפשר למשתמש לשנות את סוג המפה.
  2. מזיזים את המפה כדי לפתוח את מיקום הבית שלכם.
  3. להוסיף תמיכה בסמנים שמציינים מיקומים יחידים במפה ויכולים לכלול תווית.

הוספת תפריט לסוגי מפות

בשלב זה מוסיפים סרגל אפליקציות עם תפריט אפשרויות שמאפשר למשתמש לשנות את סוג המפה.

  1. כדי ליצור קובץ XML חדש, לוחצים לחיצה ימנית על ספריית res ובוחרים באפשרות חדש > קובץ משאבים של Android.
  2. בתיבת הדו-שיח, נותנים לקובץ את השם map_options.
  3. בוחרים באפשרות תפריט עבור סוג המשאב.
  4. לוחצים על אישור.
  5. בכרטיסייה קוד, מחליפים את הקוד בקובץ החדש בקוד הבא כדי ליצור את אפשרויות תפריט המפה. הסוג של &מירכאות;none" תנועה מושמטת כי &jpg;none" לא מתקבל בכלל מפה כלשהי. שלב זה גורם לשגיאה, אבל אתם פותרים אותו בשלב הבא.
<?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. ב-strings.xml, יש להוסיף משאבים למאפיין title כדי לפתור את השגיאות.
<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. ב-MapsActivity, יש לעקוף את השיטה onCreateOptionsMenu() ולנפח את התפריט מתוך קובץ המשאב map_options.
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
   val inflater = menuInflater
   inflater.inflate(R.menu.map_options, menu)
   return true
}
  1. בMapsActivity.kt, יש לשנות את השיטה onOptionsItemSelected(). משנים את סוג המפה באמצעות קבועים מסוג מפה כך שישקפו את בחירת המשתמש.
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. מריצים את האפליקציה.
  2. כדי לשנות את סוג המפה צריך ללחוץ על . שימו לב איך המראה של המפה משתנה בין המצבים השונים.

כברירת מחדל, הקריאה החוזרת (onMapReady()) בהתקשרות כוללת קוד שמציב סמן בסידני, אוסטרליה, שבו נוצר מפות Google. הקריאה החוזרת (callback) המוגדרת כברירת מחדל גם מוסיפה את המפה להזזה לסידני.

במשימה הזו, עליך להזיז את המצלמה של המפה לבית, לשנות את מרחק התצוגה עד לנקודה מסוימת שבחרת ולהציב שם סמן.

שלב 1: התקרבות לבית והוספת סמן

  1. בקובץ MapsActivity.kt, מאתרים את השיטה onMapReady(). הסירו את הקוד שמציב את הסמן בסידני ומזיז את המצלמה. כך צריכה להיראות שיטה שלך עכשיו.
override fun onMapReady(googleMap: GoogleMap) {
   map = googleMap

}
  1. מחפשים את קווי האורך והרוחב של הבית שלכם לפי ההוראות האלה.
  2. יוצרים ערך עבור קו הרוחב וערך עבור קו האורך, ומזינים את ערכי הצף שלהם.
val latitude = 37.422160
val longitude = -122.084270
  1. יצירת אובייקט LatLng חדש בשם homeLatLng. באובייקט homeLatLng, יש להעביר את הערכים שיצרתם עכשיו.
val homeLatLng = LatLng(latitude, longitude)
  1. אפשר ליצור val לציון המרחק מהתצוגה במפה. שינוי מרחק התצוגה 15f.
val zoomLevel = 15f

רמת המרחק מהתצוגה קובעת את המרחק מהתצוגה במפה. הרשימה הבאה מספקת מושג לגבי רמת הפירוט המוצגת לכל רמת זום:

  • 1: בעולם
  • 5: יבשה/יבשת
  • 10: עיר
  • 15: רחובות
  • 20: בניינים
  1. יש להעביר את המצלמה אל homeLatLng על ידי קריאה לפונקציה moveCamera() באובייקט map והעברה של אובייקט CameraUpdate באמצעות CameraUpdateFactory.newLatLngZoom(). יש להעביר את האובייקט homeLatLng ואת zoomLevel.
map.moveCamera(CameraUpdateFactory.newLatLngZoom(homeLatLng, zoomLevel))
  1. הוספת סמן למפה ב-homeLatLng.
map.addMarker(MarkerOptions().position(homeLatLng))

השיטה הסופית אמורה להיראות כך:

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. מריצים את האפליקציה. המפה צריכה להזיז את הבית, לשנות את מרחק התצוגה לרמה הרצויה ולהציב סמן בבית.

שלב 2: מאפשרים למשתמשים להוסיף סמן בלחיצה ארוכה

בשלב זה מוסיפים סמן כשהמשתמש נוגע במיקום ומחזיק את המיקום שלו במפה.

  1. יוצרים גרש שיטה ב-MapsActivity, שמכונה setMapLongClick() ומגדיר את GoogleMap כארגומנט.
  2. צירוף אובייקט מסוג setOnMapLongClickListener לאובייקט המפה.
private fun setMapLongClick(map:GoogleMap) {
   map.setOnMapLongClickListener { }
}
  1. בsetOnMapLongClickListener(), יש להתקשר לשיטה addMarker(). יש להעביר אובייקט MarkerOptions חדש עם המיקום המוגדר כ-LatLng שהועבר.
private fun setMapLongClick(map: GoogleMap) {
   map.setOnMapLongClickListener { latLng ->
       map.addMarker(
           MarkerOptions()
               .position(latLng)
       )
   }
}
  1. בסוף השיטה onMapReady() צריך להתקשר אל setMapLongClick() עם map.
override fun onMapReady(googleMap: GoogleMap) {
   ...
  
   setMapLongClick(map)
}
  1. מפעילים את האפליקציה.
  2. לוחצים לחיצה ארוכה על המפה כדי למקם סמן במיקום מסוים.
  3. מקישים על הסמן, שהוא מרכז אותו במסך.

שלב 3: מוסיפים חלון מידע לסמן

בשלב זה מוסיפים InfoWindow שמציג את הקואורדינטות של הסמן כאשר מקישים על הסמן.

  1. בsetMapLongClick()setOnMapLongClickListener(), יש ליצור val עבור snippet. קטע טקסט הוא טקסט נוסף המוצג אחרי הכותרת. קטע הטקסט מציג את קווי האורך והרוחב של סמן.
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. ב-addMarker(), צריך להגדיר את title של הסמן כסיכה שמוקמה באמצעות משאב מחרוזת R.string.dropped_pin.
  2. מגדירים את הסמן's snippet כ-snippet.

הפונקציה שבוצעה נראית כך:

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. מפעילים את האפליקציה.
  2. לוחצים לחיצה ארוכה על המפה כדי לשחרר סמן של מיקום.
  3. מקישים על הסמן כדי להציג את חלון המידע.

שלב 4: הוספת event listener

כברירת מחדל, נקודות עניין מופיעות במפה יחד עם הסמלים שלהן. נקודות עניין כוללות פארקים, בתי ספר, בניינים ממשלתיים ועוד. כשסוג המפה מוגדר ל-normal, יופיעו במפה גם נקודות עניין עסקיות. נקודות עניין עסקיות מייצגות עסקים, כמו חנויות, מסעדות ומלונות.

בשלב זה מוסיפים GoogleMap.OnPoiClickListener למפה. event listener מסוג זה מציב סמן במפה באופן מיידי כשהמשתמש לוחץ על נקודת עניין. event listener מציג גם חלון מידע המכיל את שם נקודת העניין.

  1. יוצרים גרש שיטה ב-MapsActivity, שמכונה setPoiClick() ומגדיר את GoogleMap כארגומנט.
  2. בשיטה setPoiClick(), יש להגדיר OnPoiClickListener במכשיר GoogleMap שיועבר.
private fun setPoiClick(map: GoogleMap) {
   map.setOnPoiClickListener { poi ->

   }
}
  1. בsetOnPoiClickListener(), יוצרים val poiMarker לסמן .
  2. יש להגדיר את הסמן כ-map.addMarker() באמצעות MarkerOptions ולהגדיר את title כשם של נקודת העניין.
private fun setPoiClick(map: GoogleMap) {
   map.setOnPoiClickListener { poi ->
       val poiMarker = map.addMarker(
           MarkerOptions()
               .position(poi.latLng)
               .title(poi.name)
       )
   }
}
  1. בפונקציה setOnPoiClickListener(), צריך להתקשר אל showInfoWindow() ב-poiMarker כדי להציג מיד את חלון המידע.
poiMarker.showInfoWindow()

הקוד הסופי של הפונקציה setPoiClick() אמור להיראות כך.

private fun setPoiClick(map: GoogleMap) {
   map.setOnPoiClickListener { poi ->
       val poiMarker = map.addMarker(
           MarkerOptions()
               .position(poi.latLng)
               .title(poi.name)
       )
       poiMarker.showInfoWindow()
   }
}
  1. בסוף יום onMapReady(), יש להתקשר אל setPoiClick() ולעבור אל map.
override fun onMapReady(googleMap: GoogleMap) {
   ...

   setPoiClick(map)
}
  1. אפשר להפעיל את האפליקציה ולמצוא נקודת עניין, כמו פארק או בית קפה.
  2. יש להקיש על נקודת העניין כדי להציב עליה סמן ולהציג את השם של נקודת העניין בחלון מידע.

ניתן להתאים אישית את מפות Google בדרכים רבות, וכך להעניק למפה מראה ותחושה ייחודיים.

ניתן להתאים אישית אובייקט MapFragment באמצעות מאפייני ה-XML הזמינים, כפי שניתן להתאים אישית כל קטע אחר. עם זאת, בשלב זה מתאימים אישית את המראה והתחושה של התוכן של MapFragment, ומשתמשים בשיטות באובייקט GoogleMap.

כדי ליצור סגנון מותאם אישית במפה, אתם יוצרים קובץ JSON שמציין את אופן ההצגה של התכונות במפה. אין צורך ליצור את קובץ ה-JSON הזה באופן ידני. Google מספקת את האשף לעיצוב מפות ב'מפות', שיוצר עבורך את קובץ ה-JSON אחרי עיצוב הסגנון של המפה. במשימה הזו לסגנן את המפה בעיצוב של רטרו, והמשמעות היא שהמפה משתמשת בצבעי וינטג' ואתם מוסיפים כבישים צבעוניים.

שלב 1: יצירת סגנון למפה

  1. עוברים לכתובת https://mapstyle.withgoogle.com/ בדפדפן.
  2. בוחרים באפשרות יצירת סגנון.
  3. לוחצים על רטרו.

  1. לוחצים על אפשרויות נוספות.

  1. ברשימה סוג התכונה, בוחרים באפשרות כביש > מילוי.
  2. משנים את צבע הכביש לכל צבע שרוצים (למשל, ורוד).

  1. לוחצים על סיום.

  1. מעתיקים את קוד ה-JSON מתיבת הדו-שיח המתקבלת, ואם רוצים, מסתירים אותו בהערה בטקסט פשוט לשימוש בשלב הבא.

שלב 2: הוספת הסגנון למפה

  1. ב-Android Studio, בספרייה res , יוצרים ספריית משאבים וקוראים לה raw. נעשה שימוש במשאבים שבספרייה raw, כמו קוד JSON.
  2. יצירת קובץ ב-res/raw בשם map_style.json.
  3. מדביקים את קוד ה-JSON שבמטמון בקובץ הקובץ החדש.
  4. ב-MapsActivity, יוצרים משתנה TAG מעל לשיטה onCreate(). הפרטים האלה משמשים למטרות רישום ביומן.
private val TAG = MapsActivity::class.java.simpleName
  1. גם ב-MapsActivity צריך ליצור פונקציה ב-setMapStyle() שמקבלת GoogleMap.
  2. ב-setMapStyle(), יש להוסיף בלוק של try{}.
  3. בבלוק try{}, יוצרים val success כדי ליהנות מסטיילינג. (אתם מוסיפים את בלוק ה-catch הבא.)
  4. בבלוק try{}, מגדירים את סגנון ה-JSON למפה, קוראים ל-setMapStyle() באובייקט GoogleMap. יש להעביר אובייקט MapStyleOptions שטוען את קובץ ה-JSON.
  5. הקצאת התוצאה ל-success. השיטה setMapStyle() מחזירה בוליאני שמציין את סטטוס ההצלחה של ניתוח קובץ הסגנון והגדרת הסגנון.
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. יש להוסיף הצהרת if עבור success. אם הסגנון לא הצליח, מדפיסים יומן שהניתוח נכשל.
private fun setMapStyle(map: GoogleMap) {
   try {
       ...
       if (!success) {
           Log.e(TAG, "Style parsing failed.")
       }
   }
}
  1. יש להוסיף בלוק catch{} כדי לטפל במצב של קובץ סגנון חסר. בקטע catch, אם לא ניתן לטעון את הקובץ, יש להשליך את הקובץ Resources.NotFoundException.
private fun setMapStyle(map: GoogleMap) {
   try {
       ...
   } catch (e: Resources.NotFoundException) {
       Log.e(TAG, "Can't find style. Error: ", e)
   }
}

השיטה הסופית צריכה להיראות כמו קטע הקוד הבא:

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. לבסוף, יש להתקשר לשיטה setMapStyle() בשיטה onMapReady() שעוברת באובייקט GoogleMap.
override fun onMapReady(googleMap: GoogleMap) {
   ...
   setMapStyle(map)
}
  1. מפעילים את האפליקציה.
  2. יש להגדיר את המפה למצב normal והסגנון החדש צריך להיות גלוי עם כבישים בסגנון רטרו וכבישים בצבע הרצוי.

שלב 3: עיצוב הסמן

אפשר להתאים אישית את המפה עוד יותר על ידי עיצוב הסמני המפה. בשלב זה אתה משנה את הסמנים האדומים המוגדרים כברירת מחדל למשהו בסגנון מגניב יותר.

  1. בשיטה onMapLongClick(), יש להוסיף את שורת הקוד הבאה ל-MarkerOptions() של המבנה כדי להשתמש בסמן ברירת המחדל, אבל לשנות את הצבע לכחול.
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE))

עכשיו נראה onMapLongClickListener() כך:

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. מריצים את האפליקציה. הסימונים שמופיעים אחרי לחיצה ארוכה מופיעים עכשיו בכחול. לתשומת ליבך, סמנים של נקודות עניין צבעוניות עדיין אדומים כי לא הוספת סגנון לשיטה onPoiClick().

אחת הדרכים להתאים אישית את מפת Google היא באמצעות ציור מעליה. ניתן להשתמש בשיטה זו כדי להדגיש סוג מסוים של מיקום, כגון אתרי דיג פופולריים.

  • צורות: ניתן להוסיף למפה מצולעים, מצולעים ועיגולים.
  • GroundOverlay אובייקטים: שכבת-על של קרקע היא תמונה הקבועה במפה. בניגוד לסמנים, שכבות-העל של הקרקע מיועדות לפני השטח של כדור הארץ ולא למסך. סיבוב, הטיה או זום של המפה משנים את הכיוון של התמונה. שכבות-על של קרקע הן שימושיות אם ברצונך לתקן תמונה אחת באזור אחד במפה.

שלב: הוספת שכבת-על של קרקע

במשימה הזו, מוסיפים שכבת-על של קרקע בצורת Android למיקום הבית.

  1. צריך להוריד את התמונה הזו מ-Android ולשמור אותה בתיקייה res/drawable. (צריך לוודא ששם הקובץ הוא android.png.)

  1. בעוד onMapReady(), אחרי השיחה כדי להעביר את המצלמה למיקום הבית, צריך ליצור אובייקט GroundOverlayOptions.
  2. מקצים את האובייקט למשתנה בשם androidOverlay.
val androidOverlay = GroundOverlayOptions()
  1. יש להשתמש בשיטה BitmapDescriptorFactory.fromResource() כדי ליצור אובייקט BitmapDescriptor ממשאב התמונות שהורדתם.
  2. יש להעביר את האובייקט BitmapDescriptor אל שיטת image() של האובייקט GroundOverlayOptions.
val androidOverlay = GroundOverlayOptions()
   .image(BitmapDescriptorFactory.fromResource(R.drawable.android))
  1. יוצרים float overlaySize עבור הרוחב במטרים של שכבת-העל הרצויה. בדוגמה הזו, הרוחב של 100f פועל היטב.

יש להגדיר את המאפיין position עבור האובייקט GroundOverlayOptions על ידי קריאה לשיטה position() והעברתו באובייקט homeLatLng וברכיב overlaySize.

val overlaySize = 100f
val androidOverlay = GroundOverlayOptions()
   .image(BitmapDescriptorFactory.fromResource(R.drawable.android))
   .position(homeLatLng, overlaySize)
  1. התקשרות אל addGroundOverlay() באובייקט GoogleMap והעבירה את האובייקט של GroundOverlayOptions.
map.addGroundOverlay(androidOverlay)
  1. מריצים את האפליקציה.
  2. שנה את הערך של zoomLevel ל-18f כדי לראות את תמונת Android כשכבת-על.

משתמשים משתמשים במפות Google לעיתים קרובות כדי לראות את המיקום הנוכחי שלהם. כדי להציג את מיקום המכשיר במפה, אפשר להשתמש בשכבת נתוני המיקום.

שכבת נתוני המיקום מוסיפה למפה את המיקום שלי. כשהמשתמש מקיש על הלחצן, המפה מתרכזת במיקום המכשיר. המיקום מוצג כנקודה כחולה אם המכשיר הוא נייח ושבר הצגה כחול אם המכשיר זז.

במשימה הזו מפעילים את שכבת נתוני המיקום.

שלב: בקשת הרשאות מיקום

הפעלה של מעקב אחר מיקום במפות Google מחייבת שורת קוד אחת. עם זאת, עליך לוודא שהמשתמש העניק הרשאות מיקום (באמצעות מודל ההרשאה לזמן ריצה).

בשלב זה, אתם מבקשים הרשאות מיקום ומפעילים את המעקב אחר המיקום.

  1. בקובץ AndroidManifest.xml יש לוודא שההרשאה FINE_LOCATION כבר קיימת. ההרשאה הזו הופעלה על ידי Android Studio כשבחרת בתבנית של מפות Google.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  1. ב-MapsActivity, יוצרים משתנה כיתה REQUEST_LOCATION_PERMISSION.
private val REQUEST_LOCATION_PERMISSION = 1
  1. כדי לבדוק אם הרשאות הוענקו, יש ליצור שיטה ב-MapsActivity שנקראת isPermissionGranted(). בשיטה הזו, בודקים אם המשתמש נתן את ההרשאה.
private fun isPermissionGranted() : Boolean {
  return ContextCompat.checkSelfPermission(
       this,
      Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
}
  1. כדי להפעיל מעקב אחר מיקום באפליקציה שלך, יש ליצור שיטה ב-MapsActivity שנקראת enableMyLocation() שלא מקבלת ארגומנטים ולא מחזירה דבר. בתוכו, יש לבדוק אם יש לך הרשאה ב-ACCESS_FINE_LOCATION. אם ההרשאה הוענקה, מפעילים את שכבת המיקום. אם לא, מבקשים את ההרשאה.
private fun enableMyLocation() {
   if (isPermissionGranted()) {
       map.isMyLocationEnabled = true 
   }
   else {
       ActivityCompat.requestPermissions(
           this,
           arrayOf<String>(Manifest.permission.ACCESS_FINE_LOCATION),
           REQUEST_LOCATION_PERMISSION
       )
   }
}
  1. יש להתקשר אל enableMyLocation() מהשיחה החוזרת ב-onMapReady() כדי להפעיל את שכבת המיקום.
override fun onMapReady(googleMap: GoogleMap) {
   ...
   enableMyLocation()
}
  1. שינוי השיטה onRequestPermissionsResult(). אם הפרמטר requestCode שווה ל-REQUEST_LOCATION_PERMISSION, ואם המערך grantResults לא ריק עם PackageManager.PERMISSION_GRANTED במשבצת הראשונה, יש להתקשר אל enableMyLocation().
override fun onRequestPermissionsResult(
   requestCode: Int,
   permissions: Array<String>,
   grantResults: IntArray) {
   if (requestCode == REQUEST_LOCATION_PERMISSION) {
       if (grantResults.contains(PackageManager.PERMISSION_GRANTED)) {
           enableMyLocation()
       }
   }
}
  1. מפעילים את האפליקציה. אמורה להיות תיבת דו-שיח שמבקשת גישה למיקום של המכשיר. זה הזמן לתת את ההרשאה.

המפה מציגה עכשיו את המיקום הנוכחי של המכשיר באמצעות נקודה כחולה. שימו לב שיש לחצן מיקום. אם תזיזו את המפה מהמיקום שלכם ותלחצו על הלחצן הזה, היא תמרכז את המפה בחזרה למיקום המכשיר.

צריך להוריד את הקוד של מעבדת הקוד המלאה.

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


לחלופין, אפשר להוריד את המאגר כקובץ ZIP, לפתוח אותו ב-Android Studio ולפתוח אותו.

להורדת קובץ ZIP

  • כדי להשתמש ב-API של מפות Google, צריך מפתח API ממסוף Google API.
  • ב-Android Studio, השימוש בתבנית של פעילות במפות Google יוצר Activity עם SupportMapFragment יחיד בפריסת האפליקציה. התבנית גם מוסיפה את ACCESS_FINE_PERMISSION למניפסט של האפליקציה, ומטמיעה את ה-OnMapReadyCallback בפעילות שלך, ומבטלת את שיטת החובה onMapReady().

כדי לשנות את סוג המפה של GoogleMap בזמן ריצה, יש להשתמש בשיטה GoogleMap.setMapType(). ניתן לבחור באחד מסוגי המפה הבאים:

  • רגילה: מפת דרכים אופיינית. הצגת כבישים, תכונות מסוימות שנבנו על ידי בני אדם ותכונות טבעיות חשובות כמו נהרות. תוויות גם של כבישים ותכונות.
  • היברידי: נתוני תמונה מלוויין עם מפות כבישים. תוויות גם של כבישים ותכונות.
  • לוויין: צילום תמונות. תוויות של כבישים ותכונות לא גלויות.
  • פני השטח: נתונים טופוגרפיים. המפה כוללת צבעים, קווים ותוויות קווי מתאר והצללה של נקודת המבט. גם חלק מהכבישים והתוויות גלויים.
  • ללא: אין אריחי מפה בסיסית.

מידע על מפות Google:

  • סמן הוא אינדיקטור של מיקום גיאוגרפי ספציפי.
  • עם הקשה, התנהגות ברירת המחדל של הסמן היא להציג חלון מידע עם מידע על המיקום.
  • כברירת מחדל, נקודות עניין מופיעות במפת הבסיס יחד עם הסמלים שלהן. נקודות עניין כוללות פארקים, בתי ספר, בניינים ממשלתיים ועוד.
  • בנוסף, נקודות העניין של העסק (חנויות, מסעדות, בתי מלון ועוד) מופיעות במפה כברירת מחדל כשסוג המפה הוא normal.
  • אפשר לתעד קליקים על נקודות עניין באמצעות OnPoiClickListener.
  • אתם יכולים לשנות את המראה החזותי של כמעט כל הרכיבים במפת Google באמצעות אשף העיצוב. אשף הסטיילינג יוצר קובץ JSON שאתם מעבירים למפה Google דרך השיטה setMapStyle().
  • ניתן להתאים אישית את הסמנים על ידי שינוי צבע ברירת המחדל או החלפה של סמל ברירת המחדל בסמן בתמונה מותאמת אישית.

עוד מידע חשוב:

  • להשתמש בשכבת-על של קרקע כדי לתקן תמונה למיקום גיאוגרפי.
  • משתמשים באובייקט GroundOverlayOptions כדי לציין את התמונה, גודל התמונה במטרים ומיקום התמונה. יש להעביר את האובייקט הזה לשיטת GoogleMap.addGroundOverlay() כדי להגדיר את שכבת-העל במפה.
  • אפשר להפעיל את המעקב אחר המיקום על ידי הגדרה של map.isMyLocationEnabled = true, בתנאי שלאפליקציה שלך יש הרשאה ACCESS_FINE_LOCATION.
  • הוא לא נכלל במעבד הקוד הזה, אבל אתם יכולים לספק מידע נוסף על מיקום באמצעות Google Street View, שהוא תמונת פנורמה של מיקום שניתן לנווט אליו.

התיעוד של מפתח Android:

מסמכי עזר:

קישורים למעבדות אחרות של הקוד בקורס הזה זמינים בדף הנחיתה המתקדם של Android ב-Kotlin codelabs.