summaryrefslogtreecommitdiff
path: root/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java
blob: 56e8cc4ce22b9154d37bbf3e4a85fc3d6cc3ad46 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
package com.mapbox.mapboxsdk.annotations;

import android.support.annotation.FloatRange;
import android.support.annotation.Nullable;

import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapboxMap;

/**
 * MarkerView is an annotation that shows a {@link android.view.View} at a geographical location. The
 * default marker uses a provided icon. This icon can be customized using {@link IconFactory} to
 * generate an {@link Icon} using a provided image. MarkerViews are added to the map by first giving
 * a {@link LatLng} and using {@link MapboxMap#addMarker(BaseMarkerViewOptions)}. The marker view icon
 * by default is anchored at the center bottom.
 * <p>
 * If many markers are needed to be displayed on the map at once we suggest using {@link Marker}
 * instead. This class uses {@link com.mapbox.mapboxsdk.maps.MapboxMap.MarkerViewAdapter} to adapt a
 * MarkerView model to an Android SDK {@link android.view.View} object.
 * </p>
 * <p>
 * MarkerViews are designed to be interactive. They receive click events by default, and are often
 * used with event listeners to bring up info windows. An {@link InfoWindow} is displayed by default
 * when either a title or snippet is provided.
 * </p>
 */
public class MarkerView extends Marker {

  private MarkerViewManager markerViewManager;

  private float width;
  private float height;

  private float anchorU;
  private float anchorV;

  private float offsetX = MapboxConstants.UNMEASURED;
  private float offsetY = MapboxConstants.UNMEASURED;

  private float infoWindowAnchorU;
  private float infoWindowAnchorV;

  private boolean flat;
  private boolean visible = true;

  private float tiltValue;
  private float rotation;
  private float alpha = 1;

  private Icon markerViewIcon;

  private boolean selected;


  /**
   * Publicly hidden default constructor
   */
  MarkerView() {
  }

  /**
   * Creates a instance of MarkerView using the builder of MarkerView
   *
   * @param baseMarkerViewOptions the builder used to construct the MarkerView
   */
  public MarkerView(BaseMarkerViewOptions baseMarkerViewOptions) {
    super(baseMarkerViewOptions);
    this.alpha = baseMarkerViewOptions.getAlpha();
    this.anchorU = baseMarkerViewOptions.getAnchorU();
    this.anchorV = baseMarkerViewOptions.getAnchorV();
    this.infoWindowAnchorU = baseMarkerViewOptions.getInfoWindowAnchorU();
    this.infoWindowAnchorV = baseMarkerViewOptions.getInfoWindowAnchorV();
    this.flat = baseMarkerViewOptions.isFlat();
    this.rotation = baseMarkerViewOptions.getRotation();
    this.selected = baseMarkerViewOptions.selected;
  }

  float getWidth() {
    return width;
  }

  void setWidth(float width) {
    this.width = width;
  }

  float getHeight() {
    return height;
  }

  void setHeight(float height) {
    this.height = height;
  }

  /**
   * Specifies the anchor being set on a particular point of the MarkerView.
   * <p>
   * The anchor point is specified in the continuous space [0.0, 1.0] x [0.0, 1.0], where (0, 0)
   * is the top-left corner of the image, and (1, 1) is the bottom-right corner.
   * </p>
   *
   * @param u u-coordinate of the anchor, as a ratio of the image width (in the range [0, 1]).
   * @param v v-coordinate of the anchor, as a ratio of the image height (in the range [0, 1]).
   */
  public void setAnchor(@FloatRange(from = 0.0, to = 1.0) float u, @FloatRange(from = 0.0, to = 1.0) float v) {
    this.anchorU = u;
    this.anchorV = v;
    setOffset(-1, -1);
  }

  /**
   * Get the horizontal distance, normalized to [0, 1], of the anchor from the left edge.
   *
   * @return The u-value of the anchor.
   */
  public float getAnchorU() {
    return anchorU;
  }

  /**
   * Get the vertical distance, normalized to [0, 1], of the anchor from the top edge.
   *
   * @return the v-value of the anchor.
   */
  public float getAnchorV() {
    return anchorV;
  }

  /**
   * Internal method to set the calculated offset.
   * <p>
   * These are calculated based on the View bounds and the provided anchor.
   * </p>
   *
   * @param x the x-value of the offset.
   * @param y the y-value of the offset.
   */
  void setOffset(float x, float y) {
    offsetX = x;
    offsetY = y;
  }

  /**
   * Internal method to get the horizontal calculated offset.
   *
   * @return the calculated horizontal offset.
   */
  float getOffsetX() {
    return offsetX;
  }

  /**
   * Internal method to get the vertical calculated offset.
   *
   * @return the calculated vertical offset.
   */
  float getOffsetY() {
    return offsetY;
  }

  /**
   * Specifies the anchor point of the info window on the View of the MarkerView.
   * <p>
   * The anchor point is specified in the continuous space [0.0, 1.0] x [0.0, 1.0], where (0, 0)
   * is the top-left corner of the image, and (1, 1) is the bottom-right corner.
   * </p>
   * <p>
   * The default is the top middle of the View.
   * </p>
   *
   * @param u u-coordinate of the info window anchor, as a ratio of the image width (in the range [0, 1]).
   * @param v v-coordinate of the info window anchor, as a ratio of the image height (in the range [0, 1]).
   * @see #setAnchor(float, float) for more details.
   */
  public void setInfoWindowAnchor(@FloatRange(from = 0.0, to = 1.0) float u,
                                  @FloatRange(from = 0.0, to = 1.0) float v) {
    this.infoWindowAnchorU = u;
    this.infoWindowAnchorV = v;
  }

  /**
   * Get the horizontal distance, normalized to [0, 1], of the info window anchor from the left edge.
   *
   * @return the u value of the InfoWindow anchor.
   */
  public float getInfoWindowAnchorU() {
    return infoWindowAnchorU;
  }

  /**
   * Get the vertical distance, normalized to [0, 1], of the info window anchor from the top edge.
   *
   * @return the v value of the InfoWindow anchor.
   */
  public float getInfoWindowAnchorV() {
    return infoWindowAnchorV;
  }

  /**
   * Get the flat state of a MarkerView.
   *
   * @return true if the MarkerView is flat; false if the MarkerView is billboard.
   */
  public boolean isFlat() {
    return flat;
  }

  /**
   * Sets whether this MarkerView should be flat against the map (true) or a billboard facing the
   * camera (false).
   *
   * @param flat the flat state of the MarkerView.
   */
  public void setFlat(boolean flat) {
    this.flat = flat;
  }

  /**
   * Internal method to get the current tilted value of a MarkerView.
   *
   * @return the tilted value.
   */
  float getTilt() {
    return tiltValue;
  }

  /**
   * Internal method to set the current titled value of a MarkerView.
   *
   * @param tiltValue the tilted value to set.
   */
  void setTilt(@FloatRange(from = 0.0, to = MapboxConstants.MAXIMUM_TILT) float tiltValue) {
    this.tiltValue = tiltValue;
  }

  /**
   * Set the visible state of a MarkerView.
   *
   * @param visible true will make the MarkerView visible, false will hide the MarkerView.
   */
  public void setVisible(boolean visible) {
    this.visible = visible;
    if (markerViewManager != null) {
      markerViewManager.animateVisible(this, visible);
    }
  }

  /**
   * Returns the visible state of the MarkerView.
   *
   * @return the visible state.
   */
  public boolean isVisible() {
    return visible;
  }

  /**
   * Set the rotation value of the MarkerView in degrees.
   * <p>
   * Input will be limited to 0 - 360 degrees.
   * </p>
   * <p>
   * This will result in animating the rotation of the MarkerView using an rotation animator
   * from current value to the provided parameter value.
   * </p>
   *
   * @param rotation the rotation value to animate to.
   */
  public void setRotation(float rotation) {
    this.rotation = rotation;
    if (markerViewManager != null) {
      markerViewManager.setRotation(this, rotation);
    }
  }

  /**
   * Get the rotation value of the MarkerView.
   *
   * @return the rotation value.
   */
  public float getRotation() {
    return rotation;
  }

  /**
   * Get the alpha value of the MarkerView.
   *
   * @return the alpha value.
   */
  public float getAlpha() {
    return alpha;
  }

  /**
   * Set the alpha value of the MarkerView.
   * <p>
   * This will result in animating the alpha of the MarkerView using an alpha animator
   * from current value to the provided parameter value.
   * </p>
   *
   * @param alpha the alpha value to animate to.
   */
  public void setAlpha(@FloatRange(from = 0.0, to = 255.0) float alpha) {
    this.alpha = alpha;
    if (markerViewManager != null) {
      markerViewManager.animateAlpha(this, alpha);
    }
  }

  /**
   * Set the icon of the MarkerView.
   *
   * @param icon the {@link Icon} to be used as Marker image.
   */
  @Override
  public void setIcon(@Nullable Icon icon) {
    if (icon != null) {
      markerViewIcon = IconFactory.recreate(IconFactory.ICON_MARKERVIEW_ID, icon.getBitmap());
    }
    Icon transparentIcon = IconFactory.recreate(IconFactory.ICON_MARKERVIEW_ID,
      IconFactory.ICON_MARKERVIEW_BITMAP);
    if (markerViewManager != null) {
      markerViewManager.updateIcon(this);
    }
    super.setIcon(transparentIcon);
  }

  /**
   * Sets the location of the marker.
   *
   * @param position A {@link LatLng} defining the marker position.
   */
  @Override
  public void setPosition(LatLng position) {
    super.setPosition(position);
    if (markerViewManager != null) {
      markerViewManager.setWaitingForRenderInvoke(true);
      markerViewManager.update();
    }
  }

  /**
   * Determine if the {@link MarkerView} is selected or not.
   *
   * @return True if the MarkerView's selected, else false.
   */
  public boolean isSelected() {
    return selected;
  }

  /**
   * For internal use only, use {@link MapboxMap#selectMarker(Marker)} instead.
   */
  void setSelected(boolean selected) {
    this.selected = selected;
  }

  /**
   * Get the icon of the MarkerView.
   *
   * @return the icon use as Marker image.
   */
  @Override
  public Icon getIcon() {
    if (markerViewIcon == null) {
      setIcon(IconFactory.getInstance(Mapbox.getApplicationContext()).defaultMarkerView());
    }
    return markerViewIcon;
  }

  /**
   * Set the MapboxMap associated tot the MapView containing the MarkerView.
   * <p>
   * This method is used to instantiate the MarkerView and provide an instance of
   * {@link com.mapbox.mapboxsdk.maps.MapboxMap.MarkerViewAdapter}
   * </p>
   * <p>
   * This method is used to notify that a MarkerView is no longer active by setting a null value.
   * </p>
   *
   * @param mapboxMap the MapboxMap instances.
   */
  @Override
  public void setMapboxMap(MapboxMap mapboxMap) {
    super.setMapboxMap(mapboxMap);
    if (mapboxMap != null) {
      if (isFlat()) {
        // initial tilt value if MapboxMap is started with a tilt attribute
        tiltValue = (float) mapboxMap.getCameraPosition().tilt;
      }

      markerViewManager = mapboxMap.getMarkerViewManager();
    }
  }

  /**
   * Invalidates the MarkerView resulting in remeasuring the View.
   */
  void invalidate() {
    width = height = 0;
    offsetX = offsetY = MapboxConstants.UNMEASURED;
    markerViewManager.invalidateViewMarkersInVisibleRegion();
  }

  /**
   * Get the String representation of a MarkerView.
   *
   * @return the String representation.
   */
  @Override
  public String toString() {
    return "MarkerView [position[" + getPosition() + "]]";
  }
}