סמנים מציינים מיקומים בודדים במפה. ניתן להתאים אישית את הסמנים על ידי שינוי צבע ברירת המחדל, או החלפת סמל הסמן בתמונה מותאמת אישית. חלונות מידע יכולים לספק הקשר נוסף לסמן.
דוגמאות קוד
במאגר ApiDemos ב-GitHub יש דוגמה שממחישה את התכונות השונות של הסמנים:
Java
- MapWithMarker: מפה פשוטה עם סמן. קראו את המדריך בנושא הוספת מפה עם סמן.
- MarkerDemoActivity: שימוש בסמנים במפה, כולל אפשרויות ומאזינים
קוטלין
- MapWithMarker: מפה פשוטה עם סמן. קראו את המדריך בנושא הוספת מפה עם mark-kt.
- MarkerDemoActivity: שימוש בסמנים במפה, כולל אפשרויות ומאזינים
מבוא
סמנים מזהים מיקומים במפה. סמן ברירת המחדל משתמש בסמל סטנדרטי, המשותף למראה ולתחושה של מפות Google. אפשר לשנות את הצבע, התמונה או נקודת העוגן של הסמל דרך ה-API. סמנים הם אובייקטים מסוג Marker
, והם נוספים למפה באמצעות השיטה GoogleMap.addMarker(markerOptions)
.
הסמנים נועדו להיות אינטראקטיביים. הם מקבלים אירועי click
כברירת מחדל, ובדרך כלל משתמשים בהם יחד עם פונקציות event listener כדי להציג חלונות מידע. הגדרת המאפיין draggable
של סמן כ-true
מאפשרת למשתמש לשנות את מיקום הסמן. לחצו לחיצה ארוכה כדי להפעיל את היכולת להזיז את הסמן.
כברירת מחדל, כשמשתמש מקיש על סמן כלשהו, סרגל הכלים של המפה מופיע בפינה השמאלית התחתונה של המפה, ומאפשר לו גישה מהירה לאפליקציה לנייד של מפות Google. ניתן להשבית את סרגל הכלים. מידע נוסף זמין במדריך לאמצעי הבקרה.
תחילת העבודה עם סמנים
הפרק הזה של מפות בשידור חי עוסק ביסודות של הוספת סמנים למפה באמצעות ה-SDK של מפות Google ל-Android.
הוספת סמן
הדוגמה הבאה ממחישה איך להוסיף סמן למפה. הסמן נוצר בקואורדינטות -33.852,151.211
(סידני, אוסטרליה), ומציג את המחרוזת 'סמן בסידני' בחלון מידע כשלוחצים עליו.
Java
@Override public void onMapReady(GoogleMap googleMap) { // Add a marker in Sydney, Australia, // and move the map's camera to the same location. LatLng sydney = new LatLng(-33.852, 151.211); googleMap.addMarker(new MarkerOptions() .position(sydney) .title("Marker in Sydney")); googleMap.moveCamera(CameraUpdateFactory.newLatLng(sydney)); }
Kotlin
override fun onMapReady(googleMap: GoogleMap) { // Add a marker in Sydney, Australia, // and move the map's camera to the same location. val sydney = LatLng(-33.852, 151.211) googleMap.addMarker( MarkerOptions() .position(sydney) .title("Marker in Sydney") ) googleMap.moveCamera(CameraUpdateFactory.newLatLng(sydney)) }
הצגת מידע נוסף על הסמן
אחת הדרישות הנפוצות היא להציג מידע נוסף לגבי מקום או מיקום כשהמשתמש מקיש על סמן במפה. עיינו במדריך לחלונות מידע.
שיוך נתונים לסמן
אפשר לאחסן אובייקט נתונים שרירותי עם סמן באמצעות Marker.setTag()
, ולאחזר את אובייקט הנתונים באמצעות Marker.getTag()
. הדוגמה הבאה מראה איך אפשר לספור את מספר הפעמים שמשתמשים לחצו על סמן באמצעות תגים:
Java
/** * A demo class that stores and retrieves data objects with each marker. */ public class MarkerDemoActivity extends AppCompatActivity implements GoogleMap.OnMarkerClickListener, OnMapReadyCallback { private final LatLng PERTH = new LatLng(-31.952854, 115.857342); private final LatLng SYDNEY = new LatLng(-33.87365, 151.20689); private final LatLng BRISBANE = new LatLng(-27.47093, 153.0235); private Marker markerPerth; private Marker markerSydney; private Marker markerBrisbane; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_markers); SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); mapFragment.getMapAsync(this); } /** Called when the map is ready. */ @Override public void onMapReady(GoogleMap map) { // Add some markers to the map, and add a data object to each marker. markerPerth = map.addMarker(new MarkerOptions() .position(PERTH) .title("Perth")); markerPerth.setTag(0); markerSydney = map.addMarker(new MarkerOptions() .position(SYDNEY) .title("Sydney")); markerSydney.setTag(0); markerBrisbane = map.addMarker(new MarkerOptions() .position(BRISBANE) .title("Brisbane")); markerBrisbane.setTag(0); // Set a listener for marker click. map.setOnMarkerClickListener(this); } /** Called when the user clicks a marker. */ @Override public boolean onMarkerClick(final Marker marker) { // Retrieve the data from the marker. Integer clickCount = (Integer) marker.getTag(); // Check if a click count was set, then display the click count. if (clickCount != null) { clickCount = clickCount + 1; marker.setTag(clickCount); Toast.makeText(this, marker.getTitle() + " has been clicked " + clickCount + " times.", Toast.LENGTH_SHORT).show(); } // Return false to indicate that we have not consumed the event and that we wish // for the default behavior to occur (which is for the camera to move such that the // marker is centered and for the marker's info window to open, if it has one). return false; } }
Kotlin
/** * A demo class that stores and retrieves data objects with each marker. */ class MarkerDemoActivity : AppCompatActivity(), OnMarkerClickListener, OnMapReadyCallback { private val PERTH = LatLng(-31.952854, 115.857342) private val SYDNEY = LatLng(-33.87365, 151.20689) private val BRISBANE = LatLng(-27.47093, 153.0235) private var markerPerth: Marker? = null private var markerSydney: Marker? = null private var markerBrisbane: Marker? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_markers) val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment? mapFragment!!.getMapAsync(this) } /** Called when the map is ready. */ override fun onMapReady(map: GoogleMap) { // Add some markers to the map, and add a data object to each marker. markerPerth = map.addMarker( MarkerOptions() .position(PERTH) .title("Perth") ) markerPerth?.tag = 0 markerSydney = map.addMarker( MarkerOptions() .position(SYDNEY) .title("Sydney") ) markerSydney?.tag = 0 markerBrisbane = map.addMarker( MarkerOptions() .position(BRISBANE) .title("Brisbane") ) markerBrisbane?.tag = 0 // Set a listener for marker click. map.setOnMarkerClickListener(this) } /** Called when the user clicks a marker. */ override fun onMarkerClick(marker: Marker): Boolean { // Retrieve the data from the marker. val clickCount = marker.tag as? Int // Check if a click count was set, then display the click count. clickCount?.let { val newClickCount = it + 1 marker.tag = newClickCount Toast.makeText( this, "${marker.title} has been clicked $newClickCount times.", Toast.LENGTH_SHORT ).show() } // Return false to indicate that we have not consumed the event and that we wish // for the default behavior to occur (which is for the camera to move such that the // marker is centered and for the marker's info window to open, if it has one). return false } }
הנה כמה דוגמאות לתרחישים שבהם כדאי לאחסן ולאחזר נתונים באמצעות סמנים:
- האפליקציה עשויה להתאים לסוגים שונים של סמנים, וכדאי להתייחס אליהם באופן שונה כשהמשתמש לוחץ עליהם. כדי לעשות זאת, אפשר לשמור
String
עם הסמן שמציין את הסוג. - ייתכן שאתם מתקשרים עם מערכת שיש לה מזהי רשומות ייחודיים, שבהם הסמנים מייצגים רשומות ספציפיות באותה מערכת.
- נתוני הסמן עשויים להצביע על עדיפות שיש להשתמש בו כשמחליטים על מדד z של סמן.
יצירת סמן שניתן לגרירה
אפשר למקם מחדש סמן אחרי שמוסיפים אותו למפה, כל עוד המאפיין draggable
מוגדר לערך true
. לחצו לחיצה ארוכה על הסמן כדי לאפשר
גרירה. כשתסיר את האצבע מהמסך, הסמן יישאר במיקום הזה.
כברירת מחדל, לא ניתן לגרור סמנים. עליכם להגדיר את הסמן כך שיהיה ניתן לגרירה באופן מפורש באמצעות MarkerOptions.draggable(boolean)
לפני ההוספה למפה, או Marker.setDraggable(boolean)
אחרי ההוספה למפה.
אפשר להאזין לאירועי גרירה בסמן, כפי שמתואר באירועי גרירה של סמן.
קטע הקוד הבא מוסיף סמן שניתן לגרירה בפרת', אוסטרליה.
Java
final LatLng perthLocation = new LatLng(-31.90, 115.86); Marker perth = map.addMarker( new MarkerOptions() .position(perthLocation) .draggable(true));
Kotlin
val perthLocation = LatLng(-31.90, 115.86) val perth = map.addMarker( MarkerOptions() .position(perthLocation) .draggable(true) )
התאמה אישית של הסמן
בסרטון הזה מוצגות דרכים לשימוש בסמנים כדי להציג מיקומים במפה.
סמנים יכולים להגדיר תמונה מותאמת אישית שתוצג במקום סמל ברירת המחדל. הגדרת סמל כרוכה בהגדרה של מספר מאפיינים שמשפיעים על ההתנהגות החזותית של הסמן.
סמנים תומכים בהתאמה אישית באמצעות המאפיינים הבאים:
- מיקום (חובה)
- הערך
LatLng
של מיקום הסמן במפה. זהו המאפיין היחיד שנדרש לאובייקטMarker
. - עוגן
- הנקודה בתמונה שתוצב במיקום LatLng של הסמן. ברירת המחדל היא אמצע החלק התחתון של התמונה.
- אלפא
- מגדיר את השקיפות של הסמן. ברירת המחדל היא 1.0.
- כותרת
- מחרוזת שמוצגת בחלון המידע כשהמשתמש מקיש על הסמן.
- קטע קוד
- טקסט נוסף שמוצג מתחת לשם.
- סמל
- מפת סיביות שמוצגת במקום תמונת הסמן שמוגדרת כברירת מחדל.
- אפשר לגרור
- יש להגדיר את הערך כ-
true
כדי לאפשר למשתמש להזיז את הסמן. ברירת המחדל היאfalse
. - גלוי
- יש להגדיר את הערך
false
כדי להפוך את הסמן לבלתי נראה. ברירת המחדל היאtrue
. - כיוון שטוח או של לוח מודעות
- כברירת מחדל, הסמנים משתמשים בכיוון של לוח מודעות. כלומר, הם משורטטים לכיוון מסך המכשיר ולא על פני השטח של המפה. סיבוב, הטיה או שינוי מרחק התצוגה במפה לא משנים את הכיוון של הסמן. אפשר להגדיר את הכיוון של סמן כך שיהיה שטוח על פני כדור הארץ. סמנים שטוחים מסתובבים כשהמפה מסובבת, ומשנים את הפרספקטיבה כשהמפה נטויה. בדומה לסמני שלטי חוצות, סמנים שטוחים שומרים על גודלם אם מגדילים או מקטינים את התצוגה במפה.
- סיבוב
- כיוון הסמן, במעלות בכיוון השעון. מיקום ברירת המחדל משתנה אם הסמן שטוח. המיקום המוגדר כברירת מחדל לסמן שטוח הוא יישור צפונה. כשהסמן לא שטוח, מיקום ברירת המחדל פונה כלפי מעלה והסיבוב מתקבל כך שהסמן תמיד פונה למצלמה.
קטע הקוד שלמטה יוצר סמן פשוט עם סמל ברירת המחדל.
Java
final LatLng melbourneLocation = new LatLng(-37.813, 144.962); Marker melbourne = map.addMarker( new MarkerOptions() .position(melbourneLocation));
Kotlin
val melbourneLocation = LatLng(-37.813, 144.962) val melbourne = map.addMarker( MarkerOptions() .position(melbourneLocation) )
התאמה אישית של צבע הסמן
אפשר להתאים אישית את הצבע של תמונת הסמן שמוגדרת כברירת מחדל על ידי העברת אובייקט BitmapDescriptor
ל-method icon() . אפשר להשתמש בקבוצה של צבעים מוגדרים מראש באובייקט BitmapDescriptorFactory
, או להגדיר צבע סמן בהתאמה אישית באמצעות השיטה BitmapDescriptorFactory.defaultMarker(float hue)
. הגוון הוא ערך בין 0 ל-360, שמייצג נקודות בגלגל צבעים.
Java
final LatLng melbourneLocation = new LatLng(-37.813, 144.962); Marker melbourne = map.addMarker( new MarkerOptions() .position(melbourneLocation) .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE)));
Kotlin
val melbourneLocation = LatLng(-37.813, 144.962) val melbourne = map.addMarker( MarkerOptions() .position(melbourneLocation) .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE)) )
התאמה אישית של שקיפות הסמנים
ניתן לשלוט באטימות של סמן באמצעות השיטה MarkOptions.alpha() . יש לציין את Alpha כמספר ממשי (float) בין 0.0 ל-1.0, כאשר 0 הוא שקוף לחלוטין ו-1 אטום לחלוטין.
Java
final LatLng melbourneLocation = new LatLng(-37.813, 144.962); Marker melbourne = map.addMarker(new MarkerOptions() .position(melbourneLocation) .alpha(0.7f));
Kotlin
val melbourneLocation = LatLng(-37.813, 144.962) val melbourne = map.addMarker( MarkerOptions() .position(melbourneLocation) .alpha(0.7f) )
התאמה אישית של תמונת הסמן
תוכל להחליף את תמונת הסמן המוגדרת כברירת מחדל בתמונת סמן מותאמת אישית, שנקראת בדרך כלל סמל. סמלים מותאמים אישית מוגדרים תמיד בתור BitmapDescriptor
, ומוגדרים באמצעות אחת מהשיטות במחלקה BitmapDescriptorFactory
.
fromAsset(String assetName)
- יוצר סמן מותאם אישית באמצעות השם של תמונת Bitmap בספריית הנכסים.
fromBitmap(Bitmap image)
- יוצר סמן מותאם אישית מתמונה במפת סיביות.
fromFile(String fileName)
- יצירת סמל מותאם אישית באמצעות שם של קובץ תמונה של Bitmap שנמצא באחסון הפנימי.
fromPath(String absolutePath)
- יוצר סמן מותאם אישית מנתיב קובץ מוחלט של תמונה ב-Bitmap.
fromResource(int resourceId)
- יוצר סמן מותאם אישית באמצעות מזהה המשאב של תמונת מפת סיביות.
קטע הקוד שלמטה יוצר סמן עם סמל מותאם אישית.
Java
final LatLng melbourneLocation = new LatLng(-37.813, 144.962); Marker melbourne = map.addMarker( new MarkerOptions() .position(melbourneLocation) .title("Melbourne") .snippet("Population: 4,137,400") .icon(BitmapDescriptorFactory.fromResource(R.drawable.arrow)));
Kotlin
val melbourneLocation = LatLng(-37.813, 144.962) val melbourne = map.addMarker( MarkerOptions() .position(melbourneLocation) .title("Melbourne") .snippet("Population: 4,137,400") .icon(BitmapDescriptorFactory.fromResource(R.drawable.arrow)) )
יישור סמן
לרוב, סמלי סמנים משורטטים ביחס למסך. סיבוב, הטיה או שינוי מרחק התצוגה במפה לא ישנו את כיוון הסמן. אפשר להגדיר את הכיוון של סמן כך שיהיה שטוח על פני כדור הארץ. סמנים שממוקמים בצורה זו יסתובבו כשהמפה מסובבת, וזווית הצילום תשתנה במהלך הטיה של המפה. אם מגדילים או מקטינים את המפה, סמנים שטוחים נשארים בגודלם.
כדי לשנות את כיוון הסמן, יש להגדיר את מאפיין flat
של הסמן כ-true
.
Java
final LatLng perthLocation = new LatLng(-31.90, 115.86); Marker perth = map.addMarker( new MarkerOptions() .position(perthLocation) .flat(true));
Kotlin
val perthLocation = LatLng(-31.90, 115.86) val perth = map.addMarker( MarkerOptions() .position(perthLocation) .flat(true) )
סיבוב סמן
אפשר לסובב סמן מסביב לנקודת העוגן שלו באמצעות Marker
.השיטה setRotation()
. הסיבוב נמדד במעלות בכיוון השעון ממיקום ברירת המחדל. כשהסמן שטוח במפה, מיקום ברירת המחדל הוא צפון. כשהסמן לא שטוח, מיקום ברירת המחדל פונה כלפי מעלה והסיבוב מתקבל כך שהסמן תמיד פונה למצלמה.
הדוגמה הבאה מסובבת את הסמן ב-90°. הגדרת נקודת העיגון כ-0.5,0.5
גורמת לסיבוב של הסמן סביב המרכז, במקום סביב הבסיס.
Java
final LatLng perthLocation = new LatLng(-31.90, 115.86); Marker perth = map.addMarker( new MarkerOptions() .position(perthLocation) .anchor(0.5f,0.5f) .rotation(90.0f));
Kotlin
val perthLocation = LatLng(-31.90, 115.86) val perth = map.addMarker( MarkerOptions() .position(perthLocation) .anchor(0.5f, 0.5f) .rotation(90.0f) )
סמן z-index
ה-z-index מציין את סדר המקבצים של הסמן הזה, ביחס לסמנים אחרים במפה. סמן עם אינדקס z גבוה משורטט מעל לסמנים עם אינדקסי z נמוכים. ערך ברירת המחדל של z-index הוא 0
.
מגדירים את z-index באובייקט האפשרויות של הסמן על ידי קריאה ל-MarkerOptions.zIndex()
, כפי שמוצג בקטע הקוד הבא:
Java
map.addMarker(new MarkerOptions() .position(new LatLng(10, 10)) .title("Marker z1") .zIndex(1.0f));
Kotlin
map.addMarker( MarkerOptions() .position(LatLng(10.0, 10.0)) .title("Marker z1") .zIndex(1.0f) )
תוכל לגשת ל-z-index של הסמן על ידי קריאה ל-Marker.getZIndex()
, ולשנות אותו על ידי קריאה ל-Marker.setZIndex()
.
סמנים תמיד משורטטים מעל שכבות אריחים ושכבות-על אחרות שאינן סמנים (שכבות-על קרקע, קווים מרובים, פוליגונים וצורות אחרות), ללא קשר ל-z-index של שכבות-העל האחרות. סמנים נחשבים למעשה בקבוצת אינדקס Z-index נפרדת בהשוואה לשכבות-על אחרות.
מידע נוסף על ההשפעה של z-index על אירועי קליקים מופיע בהמשך.
טיפול באירועים של סמנים
ה-API של מפות Google מאפשר להאזין לאירועי סמנים ולהגיב עליהם. כדי להאזין לאירועים האלה, צריך להגדיר את ה-listener המתאים לאובייקט GoogleMap
שאליו שייכים הסמנים. כשהאירוע מתרחש באחד מהסמנים במפה, הקריאה החוזרת של המאזינים תופעל כשאובייקט Marker
התואם יועבר כפרמטר. כדי להשוות בין האובייקט Marker
לבין ההפניה שלכם לאובייקט Marker
, צריך להשתמש בפונקציה equals()
ולא ב-==
.
אפשר להאזין לאירועים הבאים:
אירועי קליקים של סמנים
תוכלו להשתמש ב-OnMarkerClickListener
כדי להאזין לאירועי לחיצה בסמן. כדי להגדיר את ה-listener הזה במפה, צריך להתקשר אל GoogleMap.setOnMarkerClickListener(OnMarkerClickListener)
. כשמשתמש ילחץ על סמן, תתבצע קריאה ל-onMarkerClick(Marker)
והסמן יועבר כארגומנט. השיטה הזאת מחזירה ערך בוליאני שמציין אם צרכתם את האירוע (כלומר, אתם רוצים להסתיר את התנהגות ברירת המחדל). אם הפונקציה מחזירה את הערך false
, ההתנהגות המוגדרת כברירת מחדל תתרחש בנוסף להתנהגות המותאמת אישית. התנהגות ברירת המחדל של אירוע של קליק של סמן היא להציג את חלון המידע שלו (אם זמין) ולהזיז את המצלמה כך שהסמן יהיה במרכז המפה.
ההשפעה של z-index על אירועי קליק:
- כאשר משתמש לוחץ על אשכול סמנים, אירוע הקליק מופעל עבור הסמן עם מדד z-index הגבוה ביותר.
- בכל קליק מופעל אירוע אחד לכל היותר. במילים אחרות, הקליק לא מועבר לסמנים או לשכבות-על אחרות עם ערכי z-index נמוכים יותר.
- לחיצה על אשכול סמנים גורמת לקליקים הבאים לעבור בין הסמנים ולבחור בכל אחד מהם בנפרד. סדר המחזור מתעדף תחילה את z-index ואחר כך את הקרבה לנקודת הקליק.
- אם המשתמש לוחץ מחוץ לאשכול, ה-API יחשב מחדש את האשכול ויאפס את המצב של מחזור הקליקים כך שהוא יתחיל מההתחלה.
- אירוע הקליק נופל דרך אשכולות של סמנים בצורות ובשכבות-על אחרות, לפני שמפעילים מחדש את המחזור.
- סמנים נחשבים למעשה בקבוצת אינדקס z נפרדת בהשוואה לשכבות-על או צורות אחרות (פוליגונים, פוליגונים, עיגולים ו/או שכבות-על קרקע), ללא קשר ל-z-index של שכבות-העל האחרות. אם מספר סמנים, שכבות-על או צורות ניצבים זה על גבי זה, אירוע הקליק מועבר בהתחלה בין אשכול הסמנים, ואז מופעל כדי ליצור שכבות-על או צורות אחרות שניתנות ללחיצה, בהתאם לערכי z-index שלהן.
אירועי גרירה של סמן
אפשר להשתמש ב-OnMarkerDragListener
כדי להאזין לאירועי גרירה בסמן. כדי להגדיר את ה-listener הזה במפה, צריך להתקשר אל GoogleMap.setOnMarkerDragListener
. כדי לגרור סמן, המשתמש צריך ללחוץ עליו לחיצה ארוכה. כשהמשתמש מסיר את האצבע מהמסך, הסמן יישאר במיקום הזה. כשגוררים סמן, המערכת מפעילה את onMarkerDragStart(Marker)
בהתחלה. בזמן שהסמן גורר, onMarkerDrag(Marker)
מופעל ללא הפסקה. בסוף הגרירה מתבצעת קריאה ל-onMarkerDragEnd(Marker)
. אפשר למצוא את מיקום הסמן בכל שלב על ידי חיוג ל-Marker.getPosition()
.