סמנים

בחירת פלטפורמה: Android iOS JavaScript

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

דוגמאות קוד

מאגר ApiDemos ב-GitHub כולל דוגמה שמדגימה תכונות סמנים שונות:

קוטלין

Java

מבוא

הסמנים מזהים מיקומים במפה. סמן ברירת המחדל משתמש בסמל רגיל, שמשותף לעיצוב ולסגנון של מפות Google. יש אפשרות לשנות את הצבע, התמונה או נקודת העוגן של הסמל באמצעות ה-API. סמנים הם אובייקטים מסוג Marker, והם מתווספים למפה באמצעות השיטה GoogleMap.addMarker(markerOptions).

הסמנים נועדו להיות אינטראקטיביים. הם מקבלים אירועי click כברירת מחדל, ולרוב משתמשים בהם בשילוב עם פונקציות event listener כדי להציג חלונות מידע. הגדרת המאפיין draggable של סמן ל-true מאפשרת למשתמש לשנות את מיקום הסמן. השתמשו בלחיצה ארוכה כדי להפעיל את היכולת להזיז את הסמן.

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

תחילת העבודה עם סמנים

בפרק הזה של מפות בשידור חי מתוארים העקרונות הבסיסיים של הוספת סמנים למפה באמצעות SDK של מפות Google ל-Android.

הוספת סמן

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

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))
}

      

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));
}

      

הצגת מידע נוסף על סמן

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

שיוך נתונים לסמן

אפשר לאחסן אובייקט נתונים שרירותי עם סמן באמצעות Marker.setTag(), ולאחזר את אובייקט הנתונים באמצעות Marker.getTag(). הדוגמה הבאה מראה איך לספור את מספר הפעמים שלחצו על סמן באמצעות תגים:

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
    }
}

      

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;
    }
}

      

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

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

הפיכת סמן לניתן לגרירה

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

כברירת מחדל, לא ניתן לגרור סמנים. עליכם להגדיר במפורש את הסמן כך שיהיה ניתן לגרירה באמצעות MarkerOptions.draggable(boolean) לפני שמוסיפים אותו למפה, או Marker.setDraggable(boolean) אחרי שמוסיפים אותו למפה. אפשר להאזין לאירועי גרירה על הסמן, כפי שמתואר באירועי גרירה של הסמן.

קטע הקוד הבא מוסיף סמן שניתן לגרירה בפרת' שבאוסטרליה.

Kotlin



val perthLocation = LatLng(-31.90, 115.86)
val perth = map.addMarker(
    MarkerOptions()
        .position(perthLocation)
        .draggable(true)
)

      

Java


final LatLng perthLocation = new LatLng(-31.90, 115.86);
Marker perth = map.addMarker(
    new MarkerOptions()
        .position(perthLocation)
        .draggable(true));

      

התאמה אישית של הסמן

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

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

הסמנים תומכים בהתאמה אישית באמצעות המאפיינים הבאים:

מיקום (חובה)
הערך LatLng של מיקום הסמן במפה. זהו המאפיין הנדרש היחיד לאובייקט Marker.
עוגן
הנקודה על התמונה שתוצב במיקום LatLng של הסמן. ערך ברירת המחדל הזה הוא אמצע החלק התחתון של התמונה.
אלפא
מגדיר את השקיפות של הסמן. ברירת המחדל היא 1.0.
שם הסרטון
מחרוזת שמוצגת בחלון המידע כשהמשתמש מקיש על הסמן.
קטע קוד
טקסט נוסף שמוצג מתחת לכותרת.
סמל
מפת סיביות שמוצגת במקום תמונת הסמן שמוגדרת כברירת מחדל.
אפשר לגרור
יש להגדיר את הערך כ-true אם ברצונך לאפשר למשתמש להזיז את הסמן. ברירת המחדל היא false.
מוצג
הגדרה כ-false כדי להפוך את הסמן לבלתי נראה. ברירת המחדל היא true.
כיוון שטוח או של לוח מודעות
כברירת מחדל, הסמנים משתמשים בכיוון של לוח מודעות. כלומר, הם משורטטים על גבי מסך המכשיר ולא על פני השטח של המפה. סיבוב, הטיה או שינוי מרחק התצוגה במפה לא משנים את כיוון הסמן. אפשר להגדיר את כיוון הסמן כך שיהיה שטוח על פני כדור הארץ. סמנים שטוחים מסתובבים כשהמפה מסובבת ומשנים את נקודת המבט כשהמפה נטויה. בדומה לסמני שלטי חוצות, סמנים שטוחים שומרים על גודלם גם אם מגדילים או מקטינים את המפה.
סיבוב
כיוון הסמן, במעלות בכיוון השעון. מיקום ברירת המחדל משתנה אם הסמן שטוח. מיקום ברירת המחדל של סמן ישר הוא יישור צפונה. כשהסמן לא שטוח, מיקום ברירת המחדל הוא מצביע למעלה וסיבוב הסיבוב הוא כך שהסמן תמיד פונה למצלמה.

קטע הקוד שלמטה יוצר סמן פשוט עם סמל ברירת המחדל.

Kotlin



val melbourneLocation = LatLng(-37.813, 144.962)
val melbourne = map.addMarker(
    MarkerOptions()
        .position(melbourneLocation)
)

      

Java


final LatLng melbourneLocation = new LatLng(-37.813, 144.962);
Marker melbourne = map.addMarker(
    new MarkerOptions()
        .position(melbourneLocation));

      

התאמה אישית של צבע הסמן

אפשר להתאים אישית את הצבע של תמונת הסימון שמוגדרת כברירת המחדל על ידי העברת אובייקט BitmapDescriptor ל-method icon() . ניתן להשתמש בקבוצה של צבעים מוגדרים מראש באובייקט BitmapDescriptorFactory, או להגדיר צבע סמן בהתאמה אישית באמצעות השיטה BitmapDescriptorFactory.defaultMarker(float hue). הגוון הוא ערך בין 0 ל-360, שמייצג נקודות על גלגל צבעים.

Kotlin



val melbourneLocation = LatLng(-37.813, 144.962)
val melbourne = map.addMarker(
    MarkerOptions()
        .position(melbourneLocation)
        .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE))
)

      

Java


final LatLng melbourneLocation = new LatLng(-37.813, 144.962);
Marker melbourne = map.addMarker(
    new MarkerOptions()
        .position(melbourneLocation)
        .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE)));

      

התאמה אישית של שקיפות הסמן

אפשר לשלוט באטימות של סמן באמצעות השיטה MarkOptions.alpha() . יש לציין את Alpha כמספר ממשי (float) בין 0.0 ל-1.0, כאשר 0 הוא שקוף לחלוטין ו-1 אטום לחלוטין.

Kotlin



val melbourneLocation = LatLng(-37.813, 144.962)
val melbourne = map.addMarker(
    MarkerOptions()
        .position(melbourneLocation)
        .alpha(0.7f)
)

      

Java


final LatLng melbourneLocation = new LatLng(-37.813, 144.962);
Marker melbourne = map.addMarker(new MarkerOptions()
    .position(melbourneLocation)
    .alpha(0.7f));

      

התאמה אישית של תמונת הסמן

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

fromAsset(String assetName)
יצירת סמן בהתאמה אישית באמצעות השם של תמונת מפת סיביות בספריית הנכסים הדיגיטליים.
fromBitmap(Bitmap image)
יצירת סמן בהתאמה אישית מתמונה במפת סיביות (bitmap).
fromFile(String fileName)
יצירת סמל מותאם אישית באמצעות השם של קובץ תמונה של מפת סיביות שנמצא באחסון הפנימי.
fromPath(String absolutePath)
יוצר סמן בהתאמה אישית מנתיב קובץ מוחלט של תמונה ב-Bitmap.
fromResource(int resourceId)
יצירת סמן מותאם אישית באמצעות מזהה המשאב של תמונת מפת סיביות (bitmap).

קטע הקוד שלמטה יוצר סמן עם סמל מותאם אישית.

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))
)

      

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)));

      

השחתת סמן

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

כדי לשנות את כיוון הסמן, מגדירים את מאפיין flat של הסמן ל-true.

Kotlin



val perthLocation = LatLng(-31.90, 115.86)
val perth = map.addMarker(
    MarkerOptions()
        .position(perthLocation)
        .flat(true)
)

      

Java


final LatLng perthLocation = new LatLng(-31.90, 115.86);
Marker perth = map.addMarker(
    new MarkerOptions()
        .position(perthLocation)
        .flat(true));

      

סיבוב הסמן

אפשר לסובב סמן מסביב לנקודת העוגן שלו באמצעות Marker.setRotation(). הסיבוב נמדד במעלות בכיוון השעון ממיקום ברירת המחדל. כשהסמן שטוח במפה, מיקום ברירת המחדל הוא צפון. כשהסמן לא שטוח, מיקום ברירת המחדל הוא מצביע למעלה והסיבוב הוא כך שהסמן תמיד פונה למצלמה.

הדוגמה הבאה מסובבת את הסמן ב-90°. הגדרת נקודת העוגן ל-0.5,0.5 גורמת לסיבוב של הסמן סביב המרכז במקום לבסיס שלו.

Kotlin



val perthLocation = LatLng(-31.90, 115.86)
val perth = map.addMarker(
    MarkerOptions()
        .position(perthLocation)
        .anchor(0.5f, 0.5f)
        .rotation(90.0f)
)

      

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));

      

סמן z-index

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

כדי להגדיר את z-index באובייקט האפשרויות של הסמן, קוראים ל-MarkerOptions.zIndex(), כפי שמוצג בקטע הקוד הבא:

Kotlin



map.addMarker(
    MarkerOptions()
        .position(LatLng(10.0, 10.0))
        .title("Marker z1")
        .zIndex(1.0f)
)

      

Java


map.addMarker(new MarkerOptions()
    .position(new LatLng(10, 10))
    .title("Marker z1")
    .zIndex(1.0f));

      

תוכל לגשת ל-z-index של הסמן על ידי קריאה ל-Marker.getZIndex(), ולשנות אותו על ידי קריאה ל-Marker.setZIndex().

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

בהמשך מוסבר ההשפעה של אינדקס z על אירועי קליקים.

טיפול באירועים של סמנים

ה-API של מפות Google מאפשר להאזין לאירועי סמנים ולהגיב עליהם. כדי להאזין לאירועים האלה, צריך להגדיר את ה-listener המתאים באובייקט GoogleMap שאליו שייכים הסמנים. כשהאירוע מתרחש באחד מהסמנים במפה, הקריאה החוזרת של המאזינים תופעל באמצעות האובייקט Marker התואם, שיועבר כפרמטר. כדי להשוות את האובייקט Marker הזה עם הפניה שלכם לאובייקט Marker, צריך להשתמש ב-equals() ולא ב-==.

אפשר להאזין לאירועים הבאים:

אירועי לחיצה של סמן

ניתן להשתמש ב-OnMarkerClickListener כדי להאזין לאירועי לחיצה על הסמן. כדי להגדיר את ה-listener הזה במפה, צריך להתקשר אל GoogleMap.setOnMarkerClickListener(OnMarkerClickListener). כשמשתמש ילחץ על סמן, תתבצע קריאה ל-onMarkerClick(Marker) והסמן יועבר כארגומנט. השיטה הזו מחזירה ערך בוליאני שמציין אם צרכתם את האירוע (כלומר, אתם רוצים להסתיר את התנהגות ברירת המחדל). אם הפונקציה מחזירה את הערך false, התנהגות ברירת המחדל תתרחש בנוסף להתנהגות המותאמת אישית. התנהגות ברירת המחדל של אירוע של לחיצה על סמן היא להציג את חלון המידע שלו (אם זמין) ולהזיז את המצלמה כך שהסמן יהיה במרכז המפה.

ההשפעה של z-index על אירועי קליק:

  • כשמשתמש לוחץ על אשכול סמנים, אירוע הקליק מופעל לסמן עם מדד ה-z הגבוה ביותר.
  • מופעל אירוע אחד לכל היותר לכל קליק. במילים אחרות, הקליק לא מועבר לסמנים או לשכבות-על אחרות עם ערכי z-index נמוכים יותר.
  • לחיצה על אשכול סמנים גורמת לקליקים הבאים לעבור בין האשכול, ולבחור בכל אחד מהם בנפרד. סדר המחזור מתעדף קודם את אינדקס z ואז את הקרבה לנקודת הקליק.
  • אם המשתמש לוחץ מחוץ לאשכול, ה-API יחשב מחדש את האשכול ויאפס את המצב של מחזור הקליקים כך שהוא יתחיל מההתחלה.
  • אירוע הקליק מחליף את אשכולות הסמנים לצורות ולשכבות-על אחרות לפני שמפעילים מחדש את המחזור.
  • סמנים נחשבים למעשה לקבוצה נפרדת של אינדקס z בהשוואה לשכבות-על או לצורות אחרות (קווים פוליגוניים, פוליגונים, עיגולים ו/או שכבות-על של קרקע), ללא קשר ל-z-index של שכבות-העל האחרות. אם מספר סמנים, שכבות-על או צורות מוצבות אחת על השנייה, אירוע הקליק עובר דרך אשכול הסמנים קודם, ואז מופעל לשכבות-על או לצורות אחרות שניתן ללחוץ עליהן, על סמך ערכי z-index שלהן.

אירועי גרירה של הסמן

ניתן להשתמש ב-OnMarkerDragListener כדי להאזין לאירועי גרירה בסמן. כדי להגדיר את ה-listener הזה במפה, צריך להתקשר אל GoogleMap.setOnMarkerDragListener. כדי לגרור סמן, משתמש צריך ללחוץ עליו לחיצה ארוכה. אם המשתמש מסיר את האצבע מהמסך, הסמן יישאר במיקום הזה. כשגוררים סמן, מתבצעת קריאה ל-onMarkerDragStart(Marker) בהתחלה. בזמן שגוררים את הסמן, הפונקציה onMarkerDrag(Marker) מופעלת כל הזמן. בסוף הגרירה מתבצעת קריאה ל-onMarkerDragEnd(Marker). אפשר למצוא את מיקום הסמן בכל שלב על ידי קריאה ל-Marker.getPosition().