Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added support for Advanced Markers #1243

Merged
merged 6 commits into from
Oct 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion demo/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ android {
dependencies {

// [START_EXCLUDE silent]
implementation 'com.google.android.gms:play-services-maps:18.1.0'
implementation project(':library')

implementation 'androidx.appcompat:appcompat:1.7.0-alpha01'
Expand Down
1 change: 1 addition & 0 deletions demo/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
<activity android:name=".BigClusteringDemoActivity" />
<activity android:name=".VisibleClusteringDemoActivity" />
<activity android:name=".CustomMarkerClusteringDemoActivity" />
<activity android:name=".CustomAdvancedMarkerClusteringDemoActivity" />
<activity android:name=".ZoomClusteringDemoActivity" />
<activity android:name=".ClusteringViewModelDemoActivity"/>
<activity android:name=".TileProviderAndProjectionDemo" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
/*
* Copyright 2023 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.maps.android.utils.demo;

import java.util.Random;

import android.graphics.Color;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.MapsInitializer;
import com.google.android.gms.maps.OnMapsSdkInitializedCallback;
import com.google.android.gms.maps.model.AdvancedMarker;
import com.google.android.gms.maps.model.AdvancedMarkerOptions;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.PinConfig;
import com.google.maps.android.clustering.Cluster;
import com.google.maps.android.clustering.ClusterItem;
import com.google.maps.android.clustering.ClusterManager;
import com.google.maps.android.clustering.view.DefaultAdvancedMarkersClusterRenderer;
import com.google.maps.android.utils.demo.model.Person;

import androidx.annotation.NonNull;

/**
* This sample demonstrates how to make use of the new Advanced Markers.
*/
public class CustomAdvancedMarkerClusteringDemoActivity extends BaseDemoActivity implements
ClusterManager.OnClusterClickListener<Person>, ClusterManager.OnClusterInfoWindowClickListener<Person>,
ClusterManager.OnClusterItemClickListener<Person>, ClusterManager.OnClusterItemInfoWindowClickListener<Person>,
OnMapsSdkInitializedCallback {
private ClusterManager<Person> mClusterManager;
private final Random mRandom = new Random(1984);

@Override
public void onMapsSdkInitialized(@NonNull MapsInitializer.Renderer renderer) {
switch (renderer) {
case LATEST:
Log.d("MapsDemo", "The latest version of the renderer is used.");
break;
case LEGACY:
Log.d("MapsDemo", "The legacy version of the renderer is used.");
break;
default:
break;
}
}

private class AdvancedMarkerRenderer extends DefaultAdvancedMarkersClusterRenderer<Person> {

public AdvancedMarkerRenderer() {
super(getApplicationContext(), getMap(), mClusterManager);
}

@Override
protected void onBeforeClusterItemRendered(@NonNull Person person,
@NonNull AdvancedMarkerOptions markerOptions) {
markerOptions
.icon(BitmapDescriptorFactory.fromPinConfig(getPinConfig().build()))
.title(person.name);
}

@Override
protected void onClusterItemUpdated(@NonNull Person person, @NonNull Marker marker) {
// Same implementation as onBeforeClusterItemRendered() (to update cached markers)
marker.setIcon(BitmapDescriptorFactory.fromPinConfig(getPinConfig().build()));
marker.setTitle(person.name);
}

private PinConfig.Builder getPinConfig() {
PinConfig.Builder pinConfigBuilder = PinConfig.builder();
pinConfigBuilder.setBackgroundColor(Color.MAGENTA);
pinConfigBuilder.setBorderColor(getResources().getColor(R.color.colorPrimaryDark));
return pinConfigBuilder;
}

private View addTextAsMarker(int size) {
TextView textView = new TextView(getApplicationContext());
textView.setText("I am a cluster of size " + size);
textView.setBackgroundColor(Color.BLACK);
textView.setTextColor(Color.YELLOW);
return textView;
}

@Override
protected void onBeforeClusterRendered(@NonNull Cluster<Person> cluster,
@NonNull AdvancedMarkerOptions markerOptions) {
markerOptions.iconView(addTextAsMarker(cluster.getSize()));
}

@Override
protected void onClusterUpdated(@NonNull Cluster<Person> cluster, AdvancedMarker marker) {
marker.setIconView(addTextAsMarker(cluster.getSize()));
}


@Override
protected boolean shouldRenderAsCluster(@NonNull Cluster<Person> cluster) {
// Always render clusters.
return cluster.getSize() > 1;
}
}


@Override
public boolean onClusterClick(Cluster<Person> cluster) {
// Show a toast with some info when the cluster is clicked.
String firstName = cluster.getItems().iterator().next().name;
Toast.makeText(this, cluster.getSize() + " (including " + firstName + ")", Toast.LENGTH_SHORT).show();

// Zoom in the cluster. Need to create LatLngBounds and including all the cluster items
// inside of bounds, then animate to center of the bounds.

// Create the builder to collect all essential cluster items for the bounds.
LatLngBounds.Builder builder = LatLngBounds.builder();
for (ClusterItem item : cluster.getItems()) {
builder.include(item.getPosition());
}
// Get the LatLngBounds
final LatLngBounds bounds = builder.build();

// Animate camera to the bounds
try {
getMap().animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 100));
} catch (Exception e) {
e.printStackTrace();
}

return true;
}

@Override
public void onClusterInfoWindowClick(Cluster<Person> cluster) {
// Does nothing, but you could go to a list of the users.
}

@Override
public boolean onClusterItemClick(Person item) {
// Does nothing, but you could go into the user's profile page, for example.
return false;
}

@Override
public void onClusterItemInfoWindowClick(Person item) {
// Does nothing, but you could go into the user's profile page, for example.
}

@Override
protected void startDemo(boolean isRestore) {
if (!isRestore) {
getMap().moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(51.503186, -0.126446), 9.5f));
}

// This line is extremely important to initialise the advanced markers. Without it, advanced markers will not work.
MapsInitializer.initialize(getApplicationContext(), MapsInitializer.Renderer.LATEST, this);

mClusterManager = new ClusterManager<>(this, getMap());
mClusterManager.setRenderer(new AdvancedMarkerRenderer());
getMap().setOnCameraIdleListener(mClusterManager);
getMap().setOnMarkerClickListener(mClusterManager);
getMap().setOnInfoWindowClickListener(mClusterManager);
mClusterManager.setOnClusterClickListener(this);
mClusterManager.setOnClusterInfoWindowClickListener(this);
mClusterManager.setOnClusterItemClickListener(this);
mClusterManager.setOnClusterItemInfoWindowClickListener(this);

addItems();
mClusterManager.cluster();
}

private void addItems() {
// http://www.flickr.com/photos/sdasmarchives/5036248203/
mClusterManager.addItem(new Person(position(), "Walter", R.drawable.walter));

// http://www.flickr.com/photos/usnationalarchives/4726917149/
mClusterManager.addItem(new Person(position(), "Gran", R.drawable.gran));

// http://www.flickr.com/photos/nypl/3111525394/
mClusterManager.addItem(new Person(position(), "Ruth", R.drawable.ruth));

// http://www.flickr.com/photos/smithsonian/2887433330/
mClusterManager.addItem(new Person(position(), "Stefan", R.drawable.stefan));

// http://www.flickr.com/photos/library_of_congress/2179915182/
mClusterManager.addItem(new Person(position(), "Mechanic", R.drawable.mechanic));

// http://www.flickr.com/photos/nationalmediamuseum/7893552556/
mClusterManager.addItem(new Person(position(), "Yeats", R.drawable.yeats));

// http://www.flickr.com/photos/sdasmarchives/5036231225/
mClusterManager.addItem(new Person(position(), "John", R.drawable.john));

// http://www.flickr.com/photos/anmm_thecommons/7694202096/
mClusterManager.addItem(new Person(position(), "Trevor the Turtle", R.drawable.turtle));

// http://www.flickr.com/photos/usnationalarchives/4726892651/
mClusterManager.addItem(new Person(position(), "Teach", R.drawable.teacher));
}

private LatLng position() {
return new LatLng(random(51.6723432, 51.38494009999999), random(0.148271, -0.3514683));
}

private double random(double min, double max) {
return mRandom.nextDouble() * (max - min) + min;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ protected void onCreate(Bundle savedInstanceState) {
mListView = findViewById(R.id.list);

addDemo("Clustering", ClusteringDemoActivity.class);
addDemo("Advanced Markers Clustering Example", CustomAdvancedMarkerClusteringDemoActivity.class);
addDemo("Clustering: Custom Look", CustomMarkerClusteringDemoActivity.class);
addDemo("Clustering: 2K markers", BigClusteringDemoActivity.class);
addDemo("Clustering: 20K only visible markers", VisibleClusteringDemoActivity.class);
Expand Down
3 changes: 3 additions & 0 deletions demo/src/main/res/layout/map.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@
~ limitations under the License.
-->

<!-- Note that the item mapId is required for Advanced Markers to work -->
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
android:id="@+id/map"
map:mapId="mapId"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.google.android.gms.maps.SupportMapFragment" />
3 changes: 2 additions & 1 deletion library/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ android {
}

dependencies {
implementation 'com.google.android.gms:play-services-maps:18.1.0'
// We are adding api() for the Maps SDK for Android, so it propagates to the app-level modules.
api 'com.google.android.gms:play-services-maps:18.2.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.core:core-ktx:1.12.0'
Expand Down
Loading