סמנים

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

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

דוגמאות קוד

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

Kotlin

Java

מבוא

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

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

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

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

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

הוסף סמן

הדוגמה הבאה ממחישה איך מוסיפים סמן למפה. הסמן הוא שנוצר בקואורדינטות -33.852,151.211 (סידני, אוסטרליה), ומציג את המחרוזת 'Marker in 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))
}

      

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-index של הסמן.

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

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

      

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

אפשר לשלוט בשקיפות של סמן באמצעות השיטה MarkerOptions.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)
יצירת סמן מותאם אישית לפי השם של תמונת Bitmap בנכסים
fromBitmap(Bitmap image)
יצירת סמן מותאם אישית מתמונה של מפת סיביות (Bitmap).
fromFile(String fileName)
יצירת סמל בהתאמה אישית באמצעות השם של קובץ תמונה בפורמט Bitmap שנמצא באחסון הפנימי.
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 של סמן

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

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

טיפול באירועי סמן

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

ניתן להאזין לאירועים הבאים:

אירועי קליק על סמן

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

ההשפעה של מדד z על אירועים מסוג קליק:

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

אירועי גרירת סמן

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