1. לפני שמתחילים
בניית אפליקציות באמצעות מפות Google מאפשרת לכם להוסיף תכונות לאפליקציה, כמו צילומי לוויין, פקדים מתקדמים בממשק המשתמש למפות, מעקב אחר מיקומים וסמני מיקום. אתם יכולים להוסיף ערך לגרסה הרגילה של מפות Google על ידי הצגת מידע ממערך הנתונים שלכם, כמו מיקומים של אזורי דיג או טיפוס ידועים. אפשר גם ליצור משחקים שבהם השחקן חוקר את העולם הפיזי, למשל בחיפוש אוצרות או אפילו במשחקי מציאות רבודה.
בשיעור הזה תיצרו אפליקציה של מפות Google בשם Wander, שמציגה מפות מותאמות אישית ומציגה את המיקום של המשתמש.
דרישות מוקדמות
ידע בנושאים הבאים:
- איך ליצור אפליקציה בסיסית ל-Android ולהריץ אותה באמצעות Android Studio
- איך ליצור ולנהל משאבים, כמו מחרוזות.
- איך לארגן מחדש קוד ולשנות שם של משתנים באמצעות Android Studio
- איך להשתמש במפת Google כמשתמש.
- איך מגדירים הרשאות בתחילת ההפעלה
מה תלמדו
- איך לקבל מפתח API מ-Google API Console ולרשום את המפתח לאפליקציה
- איך לשלב מפה של Google באפליקציה
- איך להציג סוגים שונים של מפות
- איך מעצבים את המפה של Google
- איך להוסיף סמנים למפה
- איך לאפשר למשתמש למקם סמן בנקודת עניין (POI)
- איך להפעיל מעקב אחר מיקום
- איך יוצרים את אפליקציית
Wander
שכוללת מפת Google מוטמעת - איך ליצור תכונות בהתאמה אישית לאפליקציה, כמו סמנים ועיצוב
- איך להפעיל מעקב אחר מיקום באפליקציה
2. סקירה כללית של האפליקציה
ב-Codelab הזה יוצרים את האפליקציה Wander
, שמציגה מפת Google עם עיצוב בהתאמה אישית. אפליקציית Wander מאפשרת לך לשחרר סמנים למיקומים, להוסיף שכבות-על ולראות את המיקום שלך בזמן אמת.
3. משימה: הגדרת הפרויקט וקבלת מפתח API
ל-SDK של מפות Google ל-Android נדרש מפתח API. כדי לקבל את מפתח ה-API, צריך לרשום את הפרויקט ב-API דף השירותים. מפתח ה-API מקושר לאישור דיגיטלי שמקשר את האפליקציה למחבר שלה. למידע נוסף על השימוש באישורים דיגיטליים וחתימה על האפליקציה, ראו חתימת האפליקציה.
ב-Codelab הזה משתמשים במפתח ה-API בשביל אישור ניפוי הבאגים. האישור לניפוי באגים לא מאובטח משלב התכנון, כפי שמתואר במאמר חתימה על גרסת ה-build של ניפוי הבאגים. לאפליקציות שפורסמו ל-Android שמשתמשות ב-SDK של מפות ל-Android, נדרש מפתח API שני: המפתח לאישור הגרסה. מידע נוסף על קבלת אישור גרסה זמין במאמר קבלת מפתח API.
Android Studio כולל תבנית של פעילות במפות Google, שיוצרת קוד תבנית מועיל. קוד התבנית כולל קובץ google_maps_api.xml שמכיל קישור לפשוט יותר לקבל מפתח API.
שלב 1: יוצרים את פרויקט Wander באמצעות תבנית המפות
- יוצרים פרויקט חדש של Android Studio.
- בוחרים את התבנית פעילות במפות Google.
- נותנים לפרויקט שם:
Wander
. - מגדירים את רמת ה-API המינימלית ל-API 19. חשוב לוודא שהשפה היא Kotlin.
- לוחצים על סיום.
- בסיום בניית האפליקציה, כדאי לעיין בפרויקט שלכם ובקבצים הבאים שקשורים למפות שנוצרו עבורכם ב-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
הוא הדרך הפשוטה ביותר למקם מפה באפליקציה. מדובר ב-wrapper של תצוגה של מפה כדי לטפל אוטומטית בצרכים הנדרשים של מחזור החיים.
אפשר לכלול את SupportMapFragment
בקובץ פריסה באמצעות תג <fragment>
בכל ViewGroup
, עם מאפיין name
נוסף.
android:name="com.google.android.gms.maps.SupportMapFragment"
MapsActivity.java – הקובץ MapsActivity.java מייצר את SupportMapFragment
בשיטה onCreate()
ומשתמש במחלקה. getMapAsync
()
כדי לאתחל באופן אוטומטי את מערכת המפות והתצוגה. הפעילות שמכילה את SupportMapFragment
חייבת להטמיע את הממשק של OnMapReadyCallback
ואת ה-method onMapReady()
של הממשק הזה. מתבצעת הפעלה של השיטה onMapReady()
כשהמפה נטענת.
שלב 2: מקבלים את מפתח ה-API
- פותחים את גרסת ניפוי הבאגים של הקובץ google_maps_api.xml.
- בקובץ, מחפשים תגובה עם כתובת URL ארוכה. הפרמטרים של כתובת ה-URL כוללים מידע ספציפי על האפליקציה שלכם.
- להעתיק את כתובת ה-URL ולהדביק אותה בדפדפן.
- פועלים לפי ההנחיות ליצירת פרויקט בממשקי API & דף השירותים. בגלל הפרמטרים בכתובת ה-URL שצוינה, הדף יכול להפעיל באופן אוטומטי את ה-SDK של מפות Google ל-Android.
- לוחצים על Create an API Key (יצירת מפתח API).
- בדף הבא עוברים לקטע 'מפתחות API' ולוחצים על המפתח שיצרתם.
- לוחצים על Restrict Key (הגבלת מפתח) ובוחרים באפשרות Maps SDK for Android כדי להגביל את השימוש במפתח לאפליקציות ל-Android.
- מעתיקים את מפתח ה-API שנוצר. הוא מתחיל ב-"
AIza"
. - בקובץ
google_maps_api.xml
, מדביקים את המפתח במחרוזתgoogle_maps_key
במקום שבו מופיע הכיתובYOUR_KEY_HERE
. - מפעילים את האפליקציה. אמורה להופיע מפה מוטמעת בפעילות שלך, עם סמן שמוגדר בסידני שבאוסטרליה. (הסמן של סידני הוא חלק מהתבנית, ואפשר לשנות אותו מאוחר יותר.)
שלב 3: שינוי השם של MMap
ב-MapsActivity
יש lateinit
var
פרטי בשם mMap
, מסוג GoogleMap
. כדי לפעול בהתאם למוסכמות מתן השמות של Kotlin, צריך לשנות את השם של mMap
ל-map
.
- ב-
MapsActivity
, לוחצים לחיצה ימנית עלmMap
ואז על Refactor > שינוי שם...
- משנים את שם המשתנה ל-
map
.
שימו לב איך כל ההפניות אל mMap
בפונקציה onMapReady()
משתנות גם ל-map
.
4. משימה: הוספת סוגי מפות
מפות Google כוללות מספר סוגי מפות: רגילה, היברידית, לוויינית, פני שטח ו'ללא'. (בשום אופן לא במפה).
מפה רגילה | מפת לוויין | מפה משולבת | מפת פני השטח |
כל סוג מפה מספק סוגים שונים של מידע. לדוגמה, כשמשתמשים במפות לניווט במכונית, כדאי לראות שמות של רחובות, לכן אפשר להשתמש באפשרות הרגילה. במהלך טיול רגלי, מפת פני השטח יכולה לעזור לכם להחליט כמה עוד צריך לטפס כדי להגיע לפסגה.
במשימה:
- להוסיף סרגל אפליקציה עם תפריט אפשרויות שמאפשר למשתמש לשנות את סוג המפה.
- מזיזים את המיקום ההתחלתי של המפה למיקום הבית שלכם.
- הוספת תמיכה בסמנים, שמציינים מיקומים בודדים במפה ויכולים לכלול תווית.
הוספת תפריט לסוגי המפה
בשלב הזה מוסיפים סרגל אפליקציה עם תפריט אפשרויות שמאפשר למשתמש לשנות את סוג המפה.
- כדי ליצור קובץ XML חדש של תפריט, לוחצים לחיצה ימנית על ספריית res ובוחרים באפשרות New (חדש) > קובץ משאב של Android.
- בתיבת הדו-שיח, נותנים לקובץ את השם
map_options
. - בוחרים באפשרות תפריט כדי להציג את סוג המשאב.
- לוחצים על אישור.
- בכרטיסייה Code (קוד), מחליפים את הקוד שבקובץ החדש בקוד הבא כדי ליצור את האפשרויות של תפריט המפה. האפשרות "ללא" סוג המפה הושמט מפני ש'ללא' התוצאה תהיה היעדר מפה בכלל. שלב זה גורם לשגיאה, אבל פותר אותה בשלב הבא.
<?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>
- ב-
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>
- ב-
MapsActivity
, מבטלים את השיטהonCreateOptionsMenu()
ומנפחים את התפריט מקובץ המשאביםmap_options
.
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
val inflater = menuInflater
inflater.inflate(R.menu.map_options, menu)
return true
}
- ב-
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)
}
- מפעילים את האפליקציה.
- לוחצים על כדי לשנות את סוג המפה. שימו לב איך מראה המפה משתנה בין המצבים השונים.
5. משימה: הוספת סמנים
כברירת מחדל, הקריאה החוזרת (callback) של onMapReady()
כוללת קוד שמציב סמן בסידני, אוסטרליה, שבה נוצר מפות Google. הקריאה החוזרת שמוגדרת כברירת מחדל גם יוצרת אנימציה של המפה כדי להזיז אותה לסידני.
במשימה הזאת אתם גורמים לתנועת המצלמה של המפה לעבור לבית שלכם, מגדילים את התצוגה לרמה שציינתם ומציבים שם סמן.
שלב 1: מגדילים את התצוגה של הבית ומוסיפים סמן
- בקובץ
MapsActivity.kt
, מחפשים את ה-methodonMapReady()
. הסרת הקוד בתוכו שמציב את הסמן בסידני ומזיז את המצלמה. כך אמורה להיראות השיטה שלכם עכשיו.
override fun onMapReady(googleMap: GoogleMap) {
map = googleMap
}
- כדי למצוא את קו הרוחב וקו האורך של הבית, פועלים לפי ההוראות האלה.
- יוצרים ערך לקו הרוחב וערך לקו האורך, ומזינים את הערכים הצפים שלהם.
val latitude = 37.422160
val longitude = -122.084270
- יוצרים אובייקט
LatLng
חדש בשםhomeLatLng
. באובייקטhomeLatLng
, מעבירים את הערכים שיצרתם כרגע.
val homeLatLng = LatLng(latitude, longitude)
- יוצרים
val
לקביעת מרחק התצוגה הרצוי במפה. השתמשו בזום ברמת 15f.
val zoomLevel = 15f
רמת הזום קובעת את מרחק התצוגה במפה. הרשימה הבאה מספקת מושג לגבי רמת הפירוט של כל רמת זום:
1
: עולם5
: גודל יבשתי/יבשתי10
: עיר15
: רחובות20
: מבנים
- כדי להזיז את המצלמה אל
homeLatLng
, שולחים קריאה לפונקציהmoveCamera()
על האובייקטmap
ומעבירים באובייקטCameraUpdate
באמצעותCameraUpdateFactory.newLatLngZoom()
. מעבירים את האובייקטhomeLatLng
ואתzoomLevel
.
map.moveCamera(CameraUpdateFactory.newLatLngZoom(homeLatLng, zoomLevel))
- הוספת סמן למפה ב
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))
}
- מפעילים את האפליקציה. המפה צריכה להזיז את המפה אל הבית, להתקרב לרמה הרצויה ולמקם סמן על הבית שלכם.
שלב 2: מאפשרים למשתמשים להוסיף סמן באמצעות לחיצה ארוכה
בשלב הזה, מוסיפים סמן כשהמשתמש נוגע ומחזיק מיקום במפה.
- יוצרים stub של method ב-
MapsActivity
בשםsetMapLongClick()
שלוקח אתGoogleMap
כארגומנט. - צירוף אוזן
setOnMapLongClickListener
לאובייקט המפה.
private fun setMapLongClick(map:GoogleMap) {
map.setOnMapLongClickListener { }
}
- ב-
setOnMapLongClickListener()
, מפעילים את השיטהaddMarker()
. מעבירים אובייקטMarkerOptions
חדש עם המיקום המוגדר בתורLatLng
שהועבר.
private fun setMapLongClick(map: GoogleMap) {
map.setOnMapLongClickListener { latLng ->
map.addMarker(
MarkerOptions()
.position(latLng)
)
}
}
- בסוף השיטה
onMapReady()
, קוראים לפונקציהsetMapLongClick()
עםmap
.
override fun onMapReady(googleMap: GoogleMap) {
...
setMapLongClick(map)
}
- מפעילים את האפליקציה.
- כדי להציב סמן במיקום מסוים, לוחצים לחיצה ארוכה על המפה.
- מקישים על הסמן, שמרכז אותו במסך.
שלב 3: הוספת חלון מידע לסמן
בשלב הזה, מוסיפים InfoWindow
שמציגה את הקואורדינטות של הסמן כשמקישים על הסמן.
- ב-
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)
)
}
}
- בקובץ
addMarker()
, מגדירים אתtitle
של הסמן כסיכה שמוקמה באמצעות משאב מחרוזת מסוגR.string.
dropped_pin
. - מגדירים את
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)
)
}
}
- מפעילים את האפליקציה.
- כדי להציב סמן מיקום, לוחצים לחיצה ארוכה על המפה.
- מקישים על הסמן כדי להציג את חלון המידע.
שלב 4: הוספה של מזהה נקודות עניין
כברירת מחדל, נקודות עניין (POI) מופיעות במפה יחד עם הסמלים המתאימים שלהן. נקודות העניין כוללות פארקים, בתי ספר, בנייני ממשלה ועוד. אם סוג המפה מוגדר כnormal
, נקודות עניין של העסק יופיעו במפה גם כן. נקודות עניין של עסקים מייצגות עסקים, כמו חנויות, מסעדות ומלונות.
בשלב הזה מוסיפים GoogleMap.OnPoiClickListener
למפה. אוזן הקליק הזה מציב סמן במפה מיד כשהמשתמש לוחץ על נקודת עניין. ה-click Listener מציג גם חלון מידע שמכיל את שם נקודת העניין.
- יוצרים stub של method ב-
MapsActivity
בשםsetPoiClick()
שלוקח אתGoogleMap
כארגומנט. - בשיטה
setPoiClick()
, מגדיריםOnPoiClickListener
ב-GoogleMap
שהועבר.
private fun setPoiClick(map: GoogleMap) {
map.setOnPoiClickListener { poi ->
}
}
- ב-
setOnPoiClickListener()
, יוצריםval poiMarker
עבור הסמן . - הגדרת המיקום כסמן באמצעות
map.addMarker()
כאשרMarkerOptions
מגדיר אתtitle
לשם של נקודת העניין.
private fun setPoiClick(map: GoogleMap) {
map.setOnPoiClickListener { poi ->
val poiMarker = map.addMarker(
MarkerOptions()
.position(poi.latLng)
.title(poi.name)
)
}
}
- בפונקציה
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()
}
}
- בסוף
onMapReady()
, קוראים לפונקציהsetPoiClick()
ומעבירים את ההזמנה בעודmap
.
override fun onMapReady(googleMap: GoogleMap) {
...
setPoiClick(map)
}
- מפעילים את האפליקציה ומוצאים נקודת עניין, כמו פארק או בית קפה.
- מקישים על נקודת העניין כדי להציב עליה סמן ולהציג את השם שלה בחלון מידע.
6. משימה: עיצוב המפה
אפשר להתאים אישית את מפות Google בדרכים רבות, ולהעניק למפה שלך מראה ותחושה ייחודיים.
אפשר להתאים אישית אובייקט MapFragment
באמצעות מאפייני ה-XML הזמינים, כמו שאפשר להתאים אישית כל מקטע אחר. עם זאת, בשלב הזה מתאימים אישית את המראה והתחושה של התוכן של MapFragment
, באמצעות methods של האובייקט GoogleMap
.
כדי ליצור סגנון מותאם אישית למפה, יוצרים קובץ JSON שמציין איך התכונות במפה מוצגות. אין צורך ליצור את קובץ ה-JSON הזה באופן ידני. Google מספקת את אשף עיצוב הפלטפורמה של מפות Google, שיוצר עבורכם את קובץ ה-JSON אחרי שמעצבים את המפה באופן חזותי. במשימה הזאת עיצובם את המפה לפי עיצוב רטרו. כלומר, המפה מבוססת על צבעי וינטג' ואתם מוסיפים כבישים צבעוניים.
שלב 1: יצירת סגנון למפה
- מנווטים לכתובת https://mapstyle.withgoogle.com/ בדפדפן.
- בוחרים באפשרות יצירת סגנון.
- בוחרים באפשרות רטרו.
- לוחצים על אפשרויות נוספות.
- בוחרים דרך > מילוי.
- משנים את הצבע של הדרכים לכל צבע שבוחרים (כגון ורוד).
- לוחצים על סיום.
- מעתיקים את קוד ה-JSON מתיבת הדו-שיח שמתקבלת, ואם רוצים, אפשר להסתיר אותו בפתק טקסט פשוט ולהשתמש בו בשלב הבא.
שלב 2: מוסיפים את הסגנון למפה
- בספרייה
res
ב-Android Studio, יוצרים ספריית משאבים ונותנים לה את השםraw
. אתם משתמשים במשאבים של הספרייהraw
, כמו קוד JSON. - ליצור קובץ ב-
res/raw
בשםmap_style.json
. - מדביקים את קוד ה-JSON השמור בקובץ המשאב החדש.
- בקובץ
MapsActivity
, יוצרים משתנה מחלקהTAG
מעל השיטהonCreate()
. זה משמש למטרות רישום ביומן.
private val TAG = MapsActivity::class.java.simpleName
- גם ב-
MapsActivity
, יוצרים פונקצייתsetMapStyle()
שמקבלת הפונקציהGoogleMap
. - בתיקייה
setMapStyle()
, צריך להוסיף בלוקtry{}
. - בבלוק
try{}
, יוצריםval success
כדי להצליח של העיצוב. (מוסיפים את בלוק הקליטה הבא). - בבלוק
try{}
, מגדירים את סגנון ה-JSON למפה, קוראים לפונקציהsetMapStyle()
באובייקטGoogleMap
. מעבירים אובייקטMapStyleOptions
שטוען את קובץ ה-JSON. - יש להקצות את התוצאה ל
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
)
)
}
}
- צריך להוסיף הצהרה מסוג if של
success
כ-False. אם העיצוב נכשל, מדפיסים יומן שהניתוח נכשל.
private fun setMapStyle(map: GoogleMap) {
try {
...
if (!success) {
Log.e(TAG, "Style parsing failed.")
}
}
}
- כדי לטפל במצב של קובץ סגנון חסר, מוסיפים בלוק
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)
}
}
- לסיום, קוראים ל-method
setMapStyle()
ב-methodonMapReady()
שמועברים באובייקטGoogleMap
.
override fun onMapReady(googleMap: GoogleMap) {
...
setMapStyle(map)
}
- מפעילים את האפליקציה.
- אם מגדירים את המפה למצב
normal
, העיצוב החדש יהיה גלוי עם עיצוב רטרו וכבישים בצבע שבחרתם.
שלב 3: מעצבים את הסמן
ניתן להתאים אישית את המפה עוד יותר על ידי עיצוב סמני המפה. בשלב הזה משנים את הסמנים האדומים שמוגדרים כברירת מחדל למשהו יותר מדליק.
- בשיטה
onMapLongClick()
, מוסיפים את שורת הקוד הבאה ל-MarkerOptions()
של ה-constructor כדי להשתמש בסמן ברירת המחדל, אבל משנים את הצבע לכחול.
.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))
)
}
- מפעילים את האפליקציה. הסמנים שמופיעים אחרי לחיצה ארוכה הופכים עכשיו לכחולים. לתשומת ליבך, הסמנים של נקודות העניין עדיין אדומים כי לא הוספת עיצוב ל-method
onPoiClick()
.
7. משימה: הוספת שכבת-על
אחת מהדרכים להתאים אישית את מפת Google היא באמצעות שרטוט מעליה. השיטה הזו שימושית אם רוצים להדגיש מיקום מסוג מסוים, כמו אתרי דיג פופולריים.
- צורות: אפשר להוסיף למפה קווים פוליגוניים, פוליגונים ומעגלים.
GroundOverlay
אובייקטים: שכבת-על של קרקע היא תמונה שמוצמדת למפה. בשונה מסמנים, שכבות-על של קרקע מכוונות לפני כדור הארץ ולא למסך. סיבוב, הטיה או שינוי מרחק התצוגה של המפה משנים את כיוון התמונה. שכבות-על של קרקע מועילות כשרוצים לתקן תמונה יחידה באזור אחד במפה.
שלב: הוספת שכבת-על של קרקע
במשימה הזאת תוסיפו למיקום הבית שלכם שכבת-על של קרקע בצורת מכשיר Android.
- הורד את תמונת Android הזו ושמור אותה בתיקייה
res/drawable
. (מוודאים ששם הקובץ הואandroid.png
).
- ב
onMapReady()
, אחרי הקריאה להזיז את המצלמה למיקום הבית, צריך ליצור אובייקטGroundOverlayOptions
. - מקצים את האובייקט למשתנה בשם
androidOverlay
.
val androidOverlay = GroundOverlayOptions()
- משתמשים בשיטה
BitmapDescriptorFactory.fromResource()
כדי ליצור אובייקטBitmapDescriptor
ממשאב התמונות שהורד. - מעבירים את האובייקט
BitmapDescriptor
שמתקבל ל-methodimage()
של האובייקטGroundOverlayOptions
.
val androidOverlay = GroundOverlayOptions()
.image(BitmapDescriptorFactory.fromResource(R.drawable.android))
- יוצרים
float overlaySize
בשביל הרוחב במטרים של שכבת-העל הרצויה. בדוגמה הזו, הרוחב של100f
עובד טוב.
מגדירים את המאפיין position
לאובייקט GroundOverlayOptions
על ידי קריאה ל-method position()
, ומעבירים את האובייקט homeLatLng
ואת overlaySize
.
val overlaySize = 100f
val androidOverlay = GroundOverlayOptions()
.image(BitmapDescriptorFactory.fromResource(R.drawable.android))
.position(homeLatLng, overlaySize)
- קוראים לפונקציה
addGroundOverlay()
באובייקטGoogleMap
ומעבירים את האובייקטGroundOverlayOptions
.
map.addGroundOverlay(androidOverlay)
- מפעילים את האפליקציה.
- משנים את הערך של
zoomLevel
ל-18f כדי לראות את תמונת Android כשכבת-על.
8. משימה: הפעלת מעקב אחר מיקום
לעיתים קרובות משתמשים משתמשים במפות Google כדי לראות את המיקום הנוכחי שלהם. כדי להציג את מיקום המכשיר במפה, אפשר להשתמש בשכבת נתוני המיקום.
שכבת נתוני המיקום מוסיפה למפה את הסמל המיקום שלי.
כשהמשתמש מקיש על הלחצן, המפה מתמרכזת לפי מיקום המכשיר. המיקום מוצג כנקודה כחולה אם המכשיר נמצא במצב נייח וכחץ כחול אם המכשיר נמצא בתנועה.
במשימה הזאת מפעילים את שכבת נתוני המיקום.
שלב: מבקשים הרשאות מיקום
כדי להפעיל מעקב אחר מיקום במפות Google יש שורת קוד אחת. עם זאת, צריך לוודא שהמשתמש העניק הרשאות מיקום (באמצעות המודל של הרשאת זמן ריצה).
בשלב הזה אתם מבקשים הרשאות מיקום ומפעילים את המעקב אחר המיקומים.
- בקובץ
AndroidManifest.xml
, מוודאים שההרשאהFINE_LOCATION
כבר קיימת. ההרשאה הזו נוספה ל-Android Studio כשבחרת בתבנית של מפות Google.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
- באפליקציה
MapsActivity
, יוצרים משתנה מחלקהREQUEST_LOCATION_PERMISSION
.
private val REQUEST_LOCATION_PERMISSION = 1
- כדי לבדוק אם הוענקו הרשאות, אפשר ליצור שיטה ב-
MapsActivity
בשםisPermissionGranted()
. בשיטה הזו אפשר לבדוק אם המשתמש נתן את ההרשאה.
private fun isPermissionGranted() : Boolean {
return ContextCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
}
- כדי להפעיל מעקב אחר מיקום באפליקציה שלך, עליך ליצור ב-
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
)
}
}
- צריך להפעיל את
enableMyLocation()
מהקריאה החוזרת (callback) שלonMapReady()
כדי להפעיל את שכבת המיקום.
override fun onMapReady(googleMap: GoogleMap) {
...
enableMyLocation()
}
- שינוי השיטה
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()
}
}
}
- מפעילים את האפליקציה. אמורה להופיע תיבת דו-שיח עם בקשת גישה למיקום של המכשיר. אשרו את ההרשאה.
במפה מוצג עכשיו המיקום הנוכחי של המכשיר באמצעות נקודה כחולה. שימו לב שיש לחצן מיקום. אם מרחיקים את המפה מהמיקום שלכם ותלחצו על הלחצן הזה, המפה תומרכז בחזרה למיקום של המכשיר.
9. קוד פתרון
מורידים את הקוד עבור ה-Codelab הסופי.
$ git clone https://github.com/googlecodelabs/android-kotlin-geo-maps
לחלופין, אפשר להוריד את המאגר כקובץ ZIP, לחלץ אותו ולפתוח אותו ב-Android Studio.
10. סיכום
מעולה! הוספת מפת Google לאפליקציית Android Kotlin וסגינת אותה.
11. מידע נוסף
מסמכי תיעוד למפתחים של Android:
מסמכי עזר:
12. ה-Codelab הבא
לפרטים על קישורים לשיעורי Lab אחרים בקורס הזה, ראו דף הנחיתה של שיעורי Lab מתקדמים ל-Android ב-Kotlin.