custom InfoWindow

This example shows how to Add a Marker with a Custom Info Window

  • Add a Custom view Marker with CustomMarkerOptions

  • Custom the info widow of the marker using mMap.setInfoWindowAdapter

Custom InfoWindow

For all code examples, refer to Android Maps SDK Code Examples

activity_animate_markers.xml view source

1
<?xml version="1.0" encoding="utf-8"?>
2
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
3
xmlns:app="http://schemas.android.com/apk/res-auto"
4
xmlns:tools="http://schemas.android.com/tools"
5
android:layout_width="match_parent"
6
android:layout_height="match_parent"
7
tools:context=".MainActivity">
8
9
<ai.nextbillion.maps.core.MapView
10
android:id="@+id/map_view"
11
android:layout_width="match_parent"
12
android:layout_height="match_parent"
13
app:nbmap_uiAttribution="false"
14
app:nbmap_cameraTargetLat="53.550813508267716"
15
app:nbmap_cameraTargetLng="9.992248999933745"
16
app:nbmap_cameraZoom="15" />
17
18
<ImageView
19
android:id="@+id/iv_back"
20
android:layout_width="40dp"
21
android:layout_height="40dp"
22
android:layout_marginLeft="16dp"
23
app:layout_constraintTop_toTopOf="parent"
24
app:layout_constraintLeft_toLeftOf="parent"
25
android:layout_marginTop="16dp"
26
android:background="@drawable/circle_white_bg"
27
android:src="@drawable/icon_back"
28
app:tint="@color/color_back_icon"/>
29
30
</androidx.constraintlayout.widget.ConstraintLayout>

CustomInfoWindowActivity view source

1
package ai.nextbillion;
2
3
import android.graphics.Bitmap;
4
import android.graphics.Color;
5
import android.os.Bundle;
6
import android.os.Parcel;
7
import android.os.Parcelable;
8
import android.view.LayoutInflater;
9
import android.view.View;
10
import android.widget.ImageView;
11
import android.widget.TextView;
12
13
import ai.nextbillion.maps.annotations.BaseMarkerOptions;
14
import ai.nextbillion.maps.annotations.Icon;
15
import ai.nextbillion.maps.annotations.IconFactory;
16
import ai.nextbillion.maps.annotations.Marker;
17
import ai.nextbillion.maps.core.MapView;
18
import ai.nextbillion.maps.core.NextbillionMap;
19
import ai.nextbillion.maps.core.OnMapReadyCallback;
20
import ai.nextbillion.maps.core.Style;
21
import ai.nextbillion.maps.geometry.LatLng;
22
import ai.nextbillion.utils.SymbolGenerator;
23
import androidx.annotation.NonNull;
24
import androidx.annotation.Nullable;
25
import androidx.appcompat.app.AppCompatActivity;
26
27
public class CustomInfoWindowActivity extends AppCompatActivity implements OnMapReadyCallback {
28
29
private MapView mapView;
30
private NextbillionMap mMap;
31
private ImageView ivBack;
32
33
@Override
34
protected void onCreate(Bundle savedInstanceState) {
35
super.onCreate(savedInstanceState);
36
setContentView(R.layout.activity_animate_markers);
37
38
ivBack = findViewById(R.id.iv_back);
39
mapView = findViewById(R.id.map_view);
40
mapView.onCreate(savedInstanceState);
41
mapView.getMapAsync(this);
42
43
ivBack.setOnClickListener(v -> finish());
44
}
45
46
@Override
47
public void onMapReady(@NonNull NextbillionMap nextbillionMap) {
48
mMap = nextbillionMap;
49
mMap.getStyle(new Style.OnStyleLoaded() {
50
@Override
51
public void onStyleLoaded(@NonNull Style style) {
52
customiseInfoWindow();
53
addMarker();
54
}
55
});
56
}
57
58
59
///////////////////////////////////////////////////////////////////////////
60
//
61
///////////////////////////////////////////////////////////////////////////
62
63
private Bitmap generateTextIcon() {
64
// View view = LayoutInflater.from(this).inflate(R.layout.text_marker_layout, mapView, false);
65
View view = LayoutInflater.from(this).inflate(R.layout.custom_marker_layout, mapView, false);
66
return SymbolGenerator.generate(view);
67
}
68
69
private void addMarker() {
70
Bitmap iconBitmap = generateTextIcon();
71
Icon icon = IconFactory.getInstance(this).fromBitmap(iconBitmap);
72
mMap.addMarker(new CustomMarkerOptions().icon(icon).position(new LatLng(53.55095026373886, 9.992248999933745)));
73
}
74
75
76
///////////////////////////////////////////////////////////////////////////
77
// Customise InfoWindow
78
///////////////////////////////////////////////////////////////////////////
79
80
private void customiseInfoWindow() {
81
mMap.setInfoWindowAdapter(new NextbillionMap.InfoWindowAdapter() {
82
@Nullable
83
@Override
84
public View getInfoWindow(@NonNull Marker marker) {
85
String title = marker.getTitle();
86
if (marker instanceof CustomMarker) {
87
View infoWidow = LayoutInflater.from(CustomInfoWindowActivity.this).inflate(R.layout.custom_info_window, mapView, false);
88
TextView infoText = infoWidow.findViewById(R.id.info_text);
89
// int color = ((CustomMarker) marker).getInfoWindowColor();
90
// TextView textView = defaultTextView(title);
91
// textView.setBackgroundColor(color);
92
return infoWidow;
93
}
94
95
return defaultTextView(title);
96
}
97
});
98
}
99
100
private TextView defaultTextView(String text) {
101
TextView textView = new TextView(this);
102
int sixteenDp = (int) getResources().getDimension(R.dimen.attr_margin);
103
textView.setText(text);
104
textView.setTextColor(Color.WHITE);
105
textView.setPadding(sixteenDp, sixteenDp, sixteenDp, sixteenDp);
106
return textView;
107
}
108
109
static class CustomMarker extends Marker {
110
111
private final int infoWindowColor;
112
113
public CustomMarker(BaseMarkerOptions baseMarkerOptions, int color) {
114
super(baseMarkerOptions);
115
infoWindowColor = color;
116
}
117
118
public int getInfoWindowColor() {
119
return infoWindowColor;
120
}
121
}
122
123
static class CustomMarkerOptions extends BaseMarkerOptions<CustomMarker, CustomMarkerOptions> {
124
125
private int color;
126
127
public CustomMarkerOptions() {
128
}
129
130
public CustomMarkerOptions infoWindowColor(int color) {
131
this.color = color;
132
return this;
133
}
134
135
@Override
136
public CustomMarkerOptions getThis() {
137
return this;
138
}
139
140
@Override
141
public CustomMarker getMarker() {
142
return new CustomMarker(this, color);
143
}
144
145
private CustomMarkerOptions(Parcel in) {
146
position((LatLng) in.readParcelable(LatLng.class.getClassLoader()));
147
snippet(in.readString());
148
String iconId = in.readString();
149
Bitmap iconBitmap = in.readParcelable(Bitmap.class.getClassLoader());
150
Icon icon = IconFactory.recreate(iconId, iconBitmap);
151
icon(icon);
152
title(in.readString());
153
infoWindowColor(in.readInt());
154
}
155
156
public static final Parcelable.Creator<CustomMarkerOptions> CREATOR
157
= new Parcelable.Creator<CustomMarkerOptions>() {
158
public CustomMarkerOptions createFromParcel(Parcel in) {
159
return new CustomMarkerOptions(in);
160
}
161
162
public CustomMarkerOptions[] newArray(int size) {
163
return new CustomMarkerOptions[size];
164
}
165
};
166
167
@Override
168
public int describeContents() {
169
return 0;
170
}
171
172
@Override
173
public void writeToParcel(Parcel out, int flags) {
174
out.writeParcelable(position, flags);
175
out.writeString(snippet);
176
out.writeString(icon.getId());
177
out.writeParcelable(icon.getBitmap(), flags);
178
out.writeString(title);
179
out.writeInt(color);
180
}
181
}
182
183
///////////////////////////////////////////////////////////////////////////
184
// Lifecycle
185
///////////////////////////////////////////////////////////////////////////
186
187
@Override
188
protected void onStart() {
189
super.onStart();
190
mapView.onStart();
191
}
192
193
@Override
194
protected void onResume() {
195
super.onResume();
196
mapView.onResume();
197
}
198
199
@Override
200
protected void onPause() {
201
super.onPause();
202
mapView.onPause();
203
}
204
205
@Override
206
protected void onStop() {
207
super.onStop();
208
mapView.onStop();
209
}
210
211
@Override
212
protected void onSaveInstanceState(@NonNull Bundle outState) {
213
super.onSaveInstanceState(outState);
214
mapView.onSaveInstanceState(outState);
215
}
216
217
@Override
218
protected void onDestroy() {
219
super.onDestroy();
220
mapView.onDestroy();
221
}
222
223
@Override
224
public void onLowMemory() {
225
super.onLowMemory();
226
mapView.onLowMemory();
227
}
228
}

The given code is an Android activity that demonstrates how to initialize a MapView and add a marker with a custom info window.

Initializing the MapView:

  • The MapView is instantiated and initialized in the onCreate() method using findViewById().

  • The map is asynchronously loaded using getMapAsync() and the initialization of the map is done in the callback.

Adding a Marker with a Custom Info Window:

  • The addMarker method is responsible for adding a marker to the map.

  • First, a custom icon for the marker is generated using the generateTextIcon method.

  • Then, an instance of the Icon is created from the generated bitmap icon.

  • Finally, the mMap object (NextbillionMap) adds a marker with the custom icon and specified position.

Customizing the Info Window:

  • The customiseInfoWindow method is used to customize the info window appearance.

  • It sets an info window adapter for the map using mMap.setInfoWindowAdapter.

  • In the adapter's getInfoWindow method, a custom info window view is inflated and returned if the marker is an instance of CustomMarker.

  • Otherwise, a default text view with the marker's title is returned.

The code also includes various lifecycle methods (onStart, onResume, onPause, onStop, onSaveInstanceState, onDestroy, onLowMemory) that should be implemented when using the MapView to properly manage its lifecycle and handle configuration changes.

The code includes additional classes (CustomMarker, CustomMarkerOptions) for creating custom markers with custom properties, such as info window color. These classes extend the base marker classes provided by the Nextbillion Maps SDK.

© 2024 NextBillion.ai all rights reserved.