Как добавить на карту маркер с информационным окном

В этом примере определяется местоположение на карте, где установлен маркер. Когда пользователь нажимает на маркер, появляется информационное окно.

Подробнее читайте в документации.

Начало работы

Прежде чем воспользоваться образцом кода, настройте среду разработки. Подробнее об образцах кода Maps SDK для Android

Ознакомьтесь с кодом

KotlinJava


class MarkerDemoActivity :
       
AppCompatActivity(),
       
OnMarkerClickListener,
       
OnInfoWindowClickListener,
       
OnMarkerDragListener,
       
OnInfoWindowLongClickListener,
       
OnInfoWindowCloseListener,
       
OnMapAndViewReadyListener.OnGlobalLayoutAndMapReadyListener {

   
private val TAG = MarkerDemoActivity::class.java.name

   
/** This is ok to be lateinit as it is initialised in onMapReady */
   
private lateinit var map: GoogleMap

   
/**
     * Keeps track of the last selected marker (though it may no longer be selected).  This is
     * useful for refreshing the info window.
     *
     * Must be nullable as it is null when no marker has been selected
     */

   
private var lastSelectedMarker: Marker? = null

   
private val markerRainbow = ArrayList<Marker>()

   
/** map to store place names and locations */
   
private val places = mapOf(
           
"BRISBANE" to LatLng(-27.47093, 153.0235),
           
"MELBOURNE" to LatLng(-37.81319, 144.96298),
           
"DARWIN" to LatLng(-12.4634, 130.8456),
           
"SYDNEY" to LatLng(-33.87365, 151.20689),
           
"ADELAIDE" to LatLng(-34.92873, 138.59995),
           
"PERTH" to LatLng(-31.952854, 115.857342),
           
"ALICE_SPRINGS" to LatLng(-24.6980, 133.8807)
   
)

   
/** These can be lateinit as they are set in onCreate */
   
private lateinit var topText: TextView
   
private lateinit var rotationBar: SeekBar
   
private lateinit var flatBox: CheckBox
   
private lateinit var options: RadioGroup

   
private val random = Random()

   
/** Demonstrates customizing the info window and/or its contents.  */
   
internal inner class CustomInfoWindowAdapter : InfoWindowAdapter {

       
// These are both view groups containing an ImageView with id "badge" and two
       
// TextViews with id "title" and "snippet".
       
private val window: View = layoutInflater.inflate(R.layout.custom_info_window, null)
       
private val contents: View = layoutInflater.inflate(R.layout.custom_info_contents, null)

       
override fun getInfoWindow(marker: Marker): View? {
           
if (options.checkedRadioButtonId != R.id.custom_info_window) {
               
// This means that getInfoContents will be called.
               
return null
           
}
            render
(marker, window)
           
return window
       
}

       
override fun getInfoContents(marker: Marker): View? {
           
if (options.checkedRadioButtonId != R.id.custom_info_contents) {
               
// This means that the default info contents will be used.
               
return null
           
}
            render
(marker, contents)
           
return contents
       
}

       
private fun render(marker: Marker, view: View) {
            val badge
= when (marker.title!!) {
               
"Brisbane" -> R.drawable.badge_qld
               
"Adelaide" -> R.drawable.badge_sa
               
"Sydney" -> R.drawable.badge_nsw
               
"Melbourne" -> R.drawable.badge_victoria
               
"Perth" -> R.drawable.badge_wa
               
in "Darwin Marker 1".."Darwin Marker 4" -> R.drawable.badge_nt
               
else -> 0 // Passing 0 to setImageResource will clear the image view.
           
}

            view
.findViewById<ImageView>(R.id.badge).setImageResource(badge)

           
// Set the title and snippet for the custom info window
            val title
: String? = marker.title
            val titleUi
= view.findViewById<TextView>(R.id.title)

           
if (title != null) {
               
// Spannable string allows us to edit the formatting of the text.
                titleUi
.text = SpannableString(title).apply {
                    setSpan
(ForegroundColorSpan(Color.RED), 0, length, 0)
               
}
           
} else {
                titleUi
.text = ""
           
}

            val snippet
: String? = marker.snippet
            val snippetUi
= view.findViewById<TextView>(R.id.snippet)
           
if (snippet != null && snippet.length > 12) {
                snippetUi
.text = SpannableString(snippet).apply {
                    setSpan
(ForegroundColorSpan(Color.MAGENTA), 0, 10, 0)
                    setSpan
(ForegroundColorSpan(Color.BLUE), 12, snippet.length, 0)
               
}
           
} else {
                snippetUi
.text = ""
           
}
       
}
   
}

   
override fun onCreate(savedInstanceState: Bundle?) {
       
super.onCreate(savedInstanceState)
        setContentView
(R.layout.marker_demo)

        topText
= findViewById(R.id.top_text)

        rotationBar
= findViewById<SeekBar>(R.id.rotationSeekBar).apply {
            max
= 360
            setOnSeekBarChangeListener
(object: OnSeekBarChangeListener {

               
/** Called when the Rotation progress bar is moved */
               
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
                    val rotation
= seekBar?.progress?.toFloat()
                    checkReadyThen
{ markerRainbow.map { it.rotation = rotation ?: 0f } }
               
}

               
override fun onStartTrackingTouch(p0: SeekBar?) {
                   
// do nothing
               
}

               
override fun onStopTrackingTouch(p0: SeekBar?) {
                   
//do nothing
               
}

           
} )
       
}

        flatBox
= findViewById(R.id.flat)

        options
= findViewById<RadioGroup>(R.id.custom_info_window_options).apply {
            setOnCheckedChangeListener
{ _, _ ->
               
if (lastSelectedMarker?.isInfoWindowShown == true) {
                   
// Refresh the info window when the info window's content has changed.
                   
// must deal with the possibility that lastSelectedMarker has changed in
                   
// another thread between the null check and this line, do this with !!
                    lastSelectedMarker
?.showInfoWindow()
               
}
           
}
       
}

        val mapFragment
= supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment
       
OnMapAndViewReadyListener(mapFragment, this)
   
}

   
/**
     * This is the callback that is triggered when the GoogleMap has loaded and is ready for use
     */

   
override fun onMapReady(googleMap: GoogleMap?) {

       
// return early if the map was not initialised properly
        map
= googleMap ?: return

       
// create bounds that encompass every location we reference
        val boundsBuilder
= LatLngBounds.Builder()
       
// include all places we have markers for on the map
        places
.keys.map { place -> boundsBuilder.include(places.getValue(place)) }
        val bounds
= boundsBuilder.build()

       
with(map) {
           
// Hide the zoom controls as the button panel will cover it.
            uiSettings
.isZoomControlsEnabled = false

           
// Setting an info window adapter allows us to change the both the contents and
           
// look of the info window.
            setInfoWindowAdapter
(CustomInfoWindowAdapter())

           
// Set listeners for marker events.  See the bottom of this class for their behavior.
            setOnMarkerClickListener
(this@MarkerDemoActivity)
            setOnInfoWindowClickListener
(this@MarkerDemoActivity)
            setOnMarkerDragListener
(this@MarkerDemoActivity)
            setOnInfoWindowCloseListener
(this@MarkerDemoActivity)
            setOnInfoWindowLongClickListener
(this@MarkerDemoActivity)

           
// Override the default content description on the view, for accessibility mode.
           
// Ideally this string would be localised.
            setContentDescription
("Map with lots of markers.")

            moveCamera
(CameraUpdateFactory.newLatLngBounds(bounds, 50))
       
}

       
// Add lots of markers to the googleMap.
        addMarkersToMap
()

   
}

   
/**
     * Show all the specified markers on the map
     */

   
private fun addMarkersToMap() {

        val placeDetailsMap
= mutableMapOf(
               
// Uses a coloured icon
               
"BRISBANE" to PlaceDetails(
                        position
= places.getValue("BRISBANE"),
                        title
= "Brisbane",
                        snippet
= "Population: 2,074,200",
                        icon
= BitmapDescriptorFactory
                               
.defaultMarker(BitmapDescriptorFactory.HUE_AZURE)
               
),

               
// Uses a custom icon with the info window popping out of the center of the icon.
               
"SYDNEY" to PlaceDetails(
                        position
= places.getValue("SYDNEY"),
                        title
= "Sydney",
                        snippet
= "Population: 4,627,300",
                        icon
= BitmapDescriptorFactory.fromResource(R.drawable.arrow),
                        infoWindowAnchorX
= 0.5f,
                        infoWindowAnchorY
= 0.5f
               
),

               
// Will create a draggable marker. Long press to drag.
               
"MELBOURNE" to PlaceDetails(
                        position
= places.getValue("MELBOURNE"),
                        title
= "Melbourne",
                        snippet
= "Population: 4,137,400",
                        draggable
= true
               
),

               
// Use a vector drawable resource as a marker icon.
               
"ALICE_SPRINGS" to PlaceDetails(
                        position
= places.getValue("ALICE_SPRINGS"),
                        title
= "Alice Springs",
                        icon
= vectorToBitmap(
                                R
.drawable.ic_android, Color.parseColor("#A4C639"))
               
),

               
// More markers for good measure
               
"PERTH" to PlaceDetails(
                        position
= places.getValue("PERTH"),
                        title
= "Perth",
                        snippet
= "Population: 1,738,800"
               
),

               
"ADELAIDE" to PlaceDetails(
                        position
= places.getValue("ADELAIDE"),
                        title
= "Adelaide",
                        snippet
= "Population: 1,213,000"
               
)

       
)

       
// add 4 markers on top of each other in Darwin with varying z-indexes
       
(0 until 4).map {
            placeDetailsMap
.put(
               
"DARWIN ${it + 1}", PlaceDetails(
                    position
= places.getValue("DARWIN"),
                    title
= "Darwin Marker ${it + 1}",
                    snippet
= "z-index initially ${it + 1}",
                    zIndex
= it.toFloat()
               
)
           
)
       
}

       
// place markers for each of the defined locations
        placeDetailsMap
.keys.map {
           
with(placeDetailsMap.getValue(it)) {
                map
.addMarker(MarkerOptions()
                       
.position(position)
                       
.title(title)
                       
.snippet(snippet)
                       
.icon(icon)
                       
.infoWindowAnchor(infoWindowAnchorX, infoWindowAnchorY)
                       
.draggable(draggable)
                       
.zIndex(zIndex))

           
}
       
}

       
// Creates a marker rainbow demonstrating how to create default marker icons of different
       
// hues (colors).
        val numMarkersInRainbow
= 12
       
(0 until numMarkersInRainbow).mapTo(markerRainbow) {
            map
.addMarker(MarkerOptions().apply{
                position
(LatLng(
                   
-30 + 10 * Math.sin(it * Math.PI / (numMarkersInRainbow - 1)),
                   
135 - 10 * Math.cos(it * Math.PI / (numMarkersInRainbow - 1))))
                title
("Marker $it")
                icon
(BitmapDescriptorFactory.defaultMarker((it * 360 / numMarkersInRainbow)
                                                               
.toFloat()))
                flat
(flatBox.isChecked)
                rotation
(rotationBar.progress.toFloat())
           
})!!
       
}
   
}

   
/**
     * Demonstrates converting a [Drawable] to a [BitmapDescriptor],
     * for use as a marker icon.
     */

   
private fun vectorToBitmap(@DrawableRes id : Int, @ColorInt color : Int): BitmapDescriptor {
        val vectorDrawable
: Drawable? = ResourcesCompat.getDrawable(resources, id, null)
       
if (vectorDrawable == null) {
           
Log.e(TAG, "Resource not found")
           
return BitmapDescriptorFactory.defaultMarker()
       
}
        val bitmap
= Bitmap.createBitmap(vectorDrawable.intrinsicWidth,
                vectorDrawable
.intrinsicHeight, Bitmap.Config.ARGB_8888)
        val canvas
= Canvas(bitmap)
        vectorDrawable
.setBounds(0, 0, canvas.width, canvas.height)
       
DrawableCompat.setTint(vectorDrawable, color)
        vectorDrawable
.draw(canvas)
       
return BitmapDescriptorFactory.fromBitmap(bitmap)
   
}

   
/** Called when the Clear button is clicked.  */
   
@Suppress("UNUSED_PARAMETER")
    fun onClearMap
(view: View) {
        checkReadyThen
{ map.clear() }
   
}

   
/** Called when the Reset button is clicked.  */
   
@Suppress("UNUSED_PARAMETER")
    fun onResetMap
(view: View) {
        checkReadyThen
{
            map
.clear()
            addMarkersToMap
()
       
}
   
}

   
/** Called when the Flat check box is checked or unchecked */
   
@Suppress("UNUSED_PARAMETER")
    fun onToggleFlat
(view: View) {
        checkReadyThen
{ markerRainbow.map { marker -> marker.isFlat = flatBox.isChecked } }
   
}

   
//
   
// Marker related listeners.
   
//
   
override fun onMarkerClick(marker : Marker): Boolean {

       
// Markers have a z-index that is settable and gettable.
        marker
.zIndex += 1.0f
       
Toast.makeText(this, "${marker.title} z-index set to ${marker.zIndex}",
               
Toast.LENGTH_SHORT).show()

        lastSelectedMarker
= marker

       
if (marker.position == places.getValue("PERTH")) {
           
// This causes the marker at Perth to bounce into position when it is clicked.
            val handler
= Handler()
            val start
= SystemClock.uptimeMillis()
            val duration
= 1500

            val interpolator
= BounceInterpolator()

            handler
.post(object : Runnable {
               
override fun run() {
                    val elapsed
= SystemClock.uptimeMillis() - start
                    val t
= Math.max(
                           
1 - interpolator.getInterpolation(elapsed.toFloat() / duration), 0f)
                    marker
.setAnchor(0.5f, 1.0f + 2 * t)

                   
// Post again 16ms later.
                   
if (t > 0.0) {
                        handler
.postDelayed(this, 16)
                   
}
               
}
           
})
       
} else if (marker.position == places.getValue("ADELAIDE")) {
           
// This causes the marker at Adelaide to change color and alpha.
            marker
.apply {
                setIcon
(BitmapDescriptorFactory.defaultMarker(random.nextFloat() * 360))
                alpha
= random.nextFloat()
           
}
       
}

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

   
override fun onInfoWindowClick(marker : Marker) {
       
Toast.makeText(this, "Click Info Window", Toast.LENGTH_SHORT).show()
   
}

   
override fun onInfoWindowClose(marker : Marker) {
       
Toast.makeText(this, "Close Info Window", Toast.LENGTH_SHORT).show()
   
}

   
override fun onInfoWindowLongClick(marker : Marker) {
       
Toast.makeText(this, "Info Window long click", Toast.LENGTH_SHORT).show()
   
}

   
override fun onMarkerDragStart(marker : Marker) {
        topText
.text = getString(R.string.on_marker_drag_start)
   
}

   
override fun onMarkerDragEnd(marker : Marker) {
        topText
.text = getString(R.string.on_marker_drag_end)
   
}

   
override fun onMarkerDrag(marker : Marker) {
        topText
.text = getString(R.string.on_marker_drag, marker.position.latitude, marker.position.longitude)
   
}

   
/**
     * Checks if the map is ready, the executes the provided lambda function
     *
     * @param stuffToDo the code to be executed if the map is ready
     */

   
private fun checkReadyThen(stuffToDo : () -> Unit) {
       
if (!::map.isInitialized) {
           
Toast.makeText(this, R.string.map_not_ready, Toast.LENGTH_SHORT).show()
       
} else {
            stuffToDo
()
       
}
   
}
}

     

public class MarkerDemoActivity extends AppCompatActivity implements
       
OnMarkerClickListener,
       
OnInfoWindowClickListener,
       
OnMarkerDragListener,
       
OnSeekBarChangeListener,
       
OnInfoWindowLongClickListener,
       
OnInfoWindowCloseListener,
       
OnMapAndViewReadyListener.OnGlobalLayoutAndMapReadyListener {

   
private static final LatLng BRISBANE = new LatLng(-27.47093, 153.0235);

   
private static final LatLng MELBOURNE = new LatLng(-37.81319, 144.96298);

   
private static final LatLng DARWIN = new LatLng(-12.4634, 130.8456);

   
private static final LatLng SYDNEY = new LatLng(-33.87365, 151.20689);

   
private static final LatLng ADELAIDE = new LatLng(-34.92873, 138.59995);

   
private static final LatLng PERTH = new LatLng(-31.952854, 115.857342);

   
private static final LatLng ALICE_SPRINGS = new LatLng(-24.6980, 133.8807);

   
/** Demonstrates customizing the info window and/or its contents. */
   
class CustomInfoWindowAdapter implements InfoWindowAdapter {

       
// These are both viewgroups containing an ImageView with id "badge" and two TextViews with id
       
// "title" and "snippet".
       
private final View mWindow;

       
private final View mContents;

       
CustomInfoWindowAdapter() {
            mWindow
= getLayoutInflater().inflate(R.layout.custom_info_window, null);
            mContents
= getLayoutInflater().inflate(R.layout.custom_info_contents, null);
       
}

       
@Override
       
public View getInfoWindow(Marker marker) {
           
if (mOptions.getCheckedRadioButtonId() != R.id.custom_info_window) {
               
// This means that getInfoContents will be called.
               
return null;
           
}
            render
(marker, mWindow);
           
return mWindow;
       
}

       
@Override
       
public View getInfoContents(Marker marker) {
           
if (mOptions.getCheckedRadioButtonId() != R.id.custom_info_contents) {
               
// This means that the default info contents will be used.
               
return null;
           
}
            render
(marker, mContents);
           
return mContents;
       
}

       
private void render(Marker marker, View view) {
           
int badge;
           
// Use the equals() method on a Marker to check for equals.  Do not use ==.
           
if (marker.equals(mBrisbane)) {
                badge
= R.drawable.badge_qld;
           
} else if (marker.equals(mAdelaide)) {
                badge
= R.drawable.badge_sa;
           
} else if (marker.equals(mSydney)) {
                badge
= R.drawable.badge_nsw;
           
} else if (marker.equals(mMelbourne)) {
                badge
= R.drawable.badge_victoria;
           
} else if (marker.equals(mPerth)) {
                badge
= R.drawable.badge_wa;
           
} else if (marker.equals(mDarwin1)) {
                badge
= R.drawable.badge_nt;
           
} else if (marker.equals(mDarwin2)) {
                badge
= R.drawable.badge_nt;
           
} else if (marker.equals(mDarwin3)) {
                badge
= R.drawable.badge_nt;
           
} else if (marker.equals(mDarwin4)) {
                badge
= R.drawable.badge_nt;
           
} else {
               
// Passing 0 to setImageResource will clear the image view.
                badge
= 0;
           
}
           
((ImageView) view.findViewById(R.id.badge)).setImageResource(badge);

           
String title = marker.getTitle();
           
TextView titleUi = ((TextView) view.findViewById(R.id.title));
           
if (title != null) {
               
// Spannable string allows us to edit the formatting of the text.
               
SpannableString titleText = new SpannableString(title);
                titleText
.setSpan(new ForegroundColorSpan(Color.RED), 0, titleText.length(), 0);
                titleUi
.setText(titleText);
           
} else {
                titleUi
.setText("");
           
}

           
String snippet = marker.getSnippet();
           
TextView snippetUi = ((TextView) view.findViewById(R.id.snippet));
           
if (snippet != null && snippet.length() > 12) {
               
SpannableString snippetText = new SpannableString(snippet);
                snippetText
.setSpan(new ForegroundColorSpan(Color.MAGENTA), 0, 10, 0);
                snippetText
.setSpan(new ForegroundColorSpan(Color.BLUE), 12, snippet.length(), 0);
                snippetUi
.setText(snippetText);
           
} else {
                snippetUi
.setText("");
           
}
       
}
   
}

   
private GoogleMap mMap;

   
private Marker mPerth;

   
private Marker mSydney;

   
private Marker mBrisbane;

   
private Marker mAdelaide;

   
private Marker mMelbourne;

   
private Marker mDarwin1;
   
private Marker mDarwin2;
   
private Marker mDarwin3;
   
private Marker mDarwin4;


   
/**
     * Keeps track of the last selected marker (though it may no longer be selected).  This is
     * useful for refreshing the info window.
     */

   
private Marker mLastSelectedMarker;

   
private final List<Marker> mMarkerRainbow = new ArrayList<Marker>();

   
private TextView mTopText;

   
private SeekBar mRotationBar;

   
private CheckBox mFlatBox;

   
private RadioGroup mOptions;

   
private final Random mRandom = new Random();

   
@Override
   
protected void onCreate(Bundle savedInstanceState) {
       
super.onCreate(savedInstanceState);
        setContentView
(R.layout.marker_demo);

        mTopText
= (TextView) findViewById(R.id.top_text);

        mRotationBar
= (SeekBar) findViewById(R.id.rotationSeekBar);
        mRotationBar
.setMax(360);
        mRotationBar
.setOnSeekBarChangeListener(this);

        mFlatBox
= (CheckBox) findViewById(R.id.flat);

        mOptions
= (RadioGroup) findViewById(R.id.custom_info_window_options);
        mOptions
.setOnCheckedChangeListener(new OnCheckedChangeListener() {
           
@Override
           
public void onCheckedChanged(RadioGroup group, int checkedId) {
               
if (mLastSelectedMarker != null && mLastSelectedMarker.isInfoWindowShown()) {
                   
// Refresh the info window when the info window's content has changed.
                    mLastSelectedMarker
.showInfoWindow();
               
}
           
}
       
});

       
SupportMapFragment mapFragment =
               
(SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
       
new OnMapAndViewReadyListener(mapFragment, this);
   
}

   
@Override
   
public void onMapReady(GoogleMap map) {
        mMap
= map;

       
// Hide the zoom controls as the button panel will cover it.
        mMap
.getUiSettings().setZoomControlsEnabled(false);

       
// Add lots of markers to the map.
        addMarkersToMap
();

       
// Setting an info window adapter allows us to change the both the contents and look of the
       
// info window.
        mMap
.setInfoWindowAdapter(new CustomInfoWindowAdapter());

       
// Set listeners for marker events.  See the bottom of this class for their behavior.
        mMap
.setOnMarkerClickListener(this);
        mMap
.setOnInfoWindowClickListener(this);
        mMap
.setOnMarkerDragListener(this);
        mMap
.setOnInfoWindowCloseListener(this);
        mMap
.setOnInfoWindowLongClickListener(this);

       
// Override the default content description on the view, for accessibility mode.
       
// Ideally this string would be localised.
        mMap
.setContentDescription("Map with lots of markers.");

       
LatLngBounds bounds = new LatLngBounds.Builder()
               
.include(PERTH)
               
.include(SYDNEY)
               
.include(ADELAIDE)
               
.include(BRISBANE)
               
.include(MELBOURNE)
               
.include(DARWIN)
               
.build();
        mMap
.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 50));
   
}

   
private void addMarkersToMap() {
       
// Uses a colored icon.
        mBrisbane
= mMap.addMarker(new MarkerOptions()
               
.position(BRISBANE)
               
.title("Brisbane")
               
.snippet("Population: 2,074,200")
               
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE)));

       
// Uses a custom icon with the info window popping out of the center of the icon.
        mSydney
= mMap.addMarker(new MarkerOptions()
               
.position(SYDNEY)
               
.title("Sydney")
               
.snippet("Population: 4,627,300")
               
.icon(BitmapDescriptorFactory.fromResource(R.drawable.arrow))
               
.infoWindowAnchor(0.5f, 0.5f));

       
// Creates a draggable marker. Long press to drag.
        mMelbourne
= mMap.addMarker(new MarkerOptions()
               
.position(MELBOURNE)
               
.title("Melbourne")
               
.snippet("Population: 4,137,400")
               
.draggable(true));

       
// Place four markers on top of each other with differing z-indexes.
        mDarwin1
= mMap.addMarker(new MarkerOptions()
               
.position(DARWIN)
               
.title("Darwin Marker 1")
               
.snippet("z-index 1")
               
.zIndex(1));
        mDarwin2
= mMap.addMarker(new MarkerOptions()
               
.position(DARWIN)
               
.title("Darwin Marker 2")
               
.snippet("z-index 2")
               
.zIndex(2));
        mDarwin3
= mMap.addMarker(new MarkerOptions()
               
.position(DARWIN)
               
.title("Darwin Marker 3")
               
.snippet("z-index 3")
               
.zIndex(3));
        mDarwin4
= mMap.addMarker(new MarkerOptions()
               
.position(DARWIN)
               
.title("Darwin Marker 4")
               
.snippet("z-index 4")
               
.zIndex(4));


       
// A few more markers for good measure.
        mPerth
= mMap.addMarker(new MarkerOptions()
               
.position(PERTH)
               
.title("Perth")
               
.snippet("Population: 1,738,800"));
        mAdelaide
= mMap.addMarker(new MarkerOptions()
               
.position(ADELAIDE)
               
.title("Adelaide")
               
.snippet("Population: 1,213,000"));

       
// Vector drawable resource as a marker icon.
        mMap
.addMarker(new MarkerOptions()
               
.position(ALICE_SPRINGS)
               
.icon(vectorToBitmap(R.drawable.ic_android, Color.parseColor("#A4C639")))
               
.title("Alice Springs"));

       
// Creates a marker rainbow demonstrating how to create default marker icons of different
       
// hues (colors).
       
float rotation = mRotationBar.getProgress();
       
boolean flat = mFlatBox.isChecked();

       
int numMarkersInRainbow = 12;
       
for (int i = 0; i < numMarkersInRainbow; i++) {
           
Marker marker = mMap.addMarker(new MarkerOptions()
                   
.position(new LatLng(
                           
-30 + 10 * Math.sin(i * Math.PI / (numMarkersInRainbow - 1)),
                           
135 - 10 * Math.cos(i * Math.PI / (numMarkersInRainbow - 1))))
                   
.title("Marker " + i)
                   
.icon(BitmapDescriptorFactory.defaultMarker(i * 360 / numMarkersInRainbow))
                   
.flat(flat)
                   
.rotation(rotation));
            mMarkerRainbow
.add(marker);
       
}
   
}

   
/**
     * Demonstrates converting a {@link Drawable} to a {@link BitmapDescriptor},
     * for use as a marker icon.
     */

   
private BitmapDescriptor vectorToBitmap(@DrawableRes int id, @ColorInt int color) {
       
Drawable vectorDrawable = ResourcesCompat.getDrawable(getResources(), id, null);
       
Bitmap bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(),
                vectorDrawable
.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
       
Canvas canvas = new Canvas(bitmap);
        vectorDrawable
.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
       
DrawableCompat.setTint(vectorDrawable, color);
        vectorDrawable
.draw(canvas);
       
return BitmapDescriptorFactory.fromBitmap(bitmap);
   
}

   
private boolean checkReady() {
       
if (mMap == null) {
           
Toast.makeText(this, R.string.map_not_ready, Toast.LENGTH_SHORT).show();
           
return false;
       
}
       
return true;
   
}

   
/** Called when the Clear button is clicked. */
   
public void onClearMap(View view) {
       
if (!checkReady()) {
           
return;
       
}
        mMap
.clear();
   
}

   
/** Called when the Reset button is clicked. */
   
public void onResetMap(View view) {
       
if (!checkReady()) {
           
return;
       
}
       
// Clear the map because we don't want duplicates of the markers.
        mMap
.clear();
        addMarkersToMap
();
   
}

   
/** Called when the Reset button is clicked. */
   
public void onToggleFlat(View view) {
       
if (!checkReady()) {
           
return;
       
}
       
boolean flat = mFlatBox.isChecked();
       
for (Marker marker : mMarkerRainbow) {
            marker
.setFlat(flat);
       
}
   
}

   
@Override
   
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
       
if (!checkReady()) {
           
return;
       
}
       
float rotation = seekBar.getProgress();
       
for (Marker marker : mMarkerRainbow) {
            marker
.setRotation(rotation);
       
}
   
}

   
@Override
   
public void onStartTrackingTouch(SeekBar seekBar) {
       
// Do nothing.
   
}

   
@Override
   
public void onStopTrackingTouch(SeekBar seekBar) {
       
// Do nothing.
   
}

   
//
   
// Marker related listeners.
   
//

   
@Override
   
public boolean onMarkerClick(final Marker marker) {
       
if (marker.equals(mPerth)) {
           
// This causes the marker at Perth to bounce into position when it is clicked.
           
final Handler handler = new Handler();
           
final long start = SystemClock.uptimeMillis();
           
final long duration = 1500;

           
final Interpolator interpolator = new BounceInterpolator();

            handler
.post(new Runnable() {
               
@Override
               
public void run() {
                   
long elapsed = SystemClock.uptimeMillis() - start;
                   
float t = Math.max(
                           
1 - interpolator.getInterpolation((float) elapsed / duration), 0);
                    marker
.setAnchor(0.5f, 1.0f + 2 * t);

                   
if (t > 0.0) {
                       
// Post again 16ms later.
                        handler
.postDelayed(this, 16);
                   
}
               
}
           
});
       
} else if (marker.equals(mAdelaide)) {
           
// This causes the marker at Adelaide to change color and alpha.
            marker
.setIcon(BitmapDescriptorFactory.defaultMarker(mRandom.nextFloat() * 360));
            marker
.setAlpha(mRandom.nextFloat());
       
}

       
// Markers have a z-index that is settable and gettable.
       
float zIndex = marker.getZIndex() + 1.0f;
        marker
.setZIndex(zIndex);
       
Toast.makeText(this, marker.getTitle() + " z-index set to " + zIndex,
               
Toast.LENGTH_SHORT).show();

        mLastSelectedMarker
= marker;
       
// We 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;
   
}

   
@Override
   
public void onInfoWindowClick(Marker marker) {
       
Toast.makeText(this, "Click Info Window", Toast.LENGTH_SHORT).show();
   
}

   
@Override
   
public void onInfoWindowClose(Marker marker) {
       
//Toast.makeText(this, "Close Info Window", Toast.LENGTH_SHORT).show();
   
}

   
@Override
   
public void onInfoWindowLongClick(Marker marker) {
       
Toast.makeText(this, "Info Window long click", Toast.LENGTH_SHORT).show();
   
}

   
@Override
   
public void onMarkerDragStart(Marker marker) {
        mTopText
.setText("onMarkerDragStart");
   
}

   
@Override
   
public void onMarkerDragEnd(Marker marker) {
        mTopText
.setText("onMarkerDragEnd");
   
}

   
@Override
   
public void onMarkerDrag(Marker marker) {
        mTopText
.setText("onMarkerDrag.  Current Position: " + marker.getPosition());
   
}

}

     

Клонирование и запуск образцов приложений

Для локального запуска образца вам потребуется Git. Используйте команду ниже, чтобы клонировать образец приложения в хранилище.

git clone git@github.com:googlemaps-samples/android-samples.git

Импортируйте образец проекта в Android Studio:

  1. В Android Studio откройте меню Файл > Создать > Импортировать проект.
  2. Перейдите в директорию, куда вы добавили хранилище, и выберите каталог проекта для Kotlin или Java.

    • Kotlin: PATH-REPO/android-samples/ApiDemos/kotlin
    • Java: PATH-REPO/android-samples/ApiDemos/java
  3. Нажмите кнопку Открыть. Android Studio создаст проект с помощью Gradle.
  4. Создайте пустой файл secrets.properties в том же каталоге, где хранится файл проекта local.properties. Подробнее о том, как добавить в проект ключ API
  5. Добавьте в secrets.properties следующую строку, заменив YOUR_API_KEY на значение вашего ключа API:

    MAPS_API_KEY=YOUR_API_KEY
  6. Запустите приложение.