summaryrefslogtreecommitdiff
path: root/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubbleLayout.java
blob: c58cc310a8ed6322ae5dedbfc125c1b213cbd517 (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
package com.mapbox.mapboxsdk.annotations;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.widget.LinearLayout;

import com.mapbox.mapboxsdk.R;

/**
 * Bubble View for Android with custom stroke width and color, arrow size, position and direction.
 */
public class BubbleLayout extends LinearLayout {

  public static final float DEFAULT_STROKE_WIDTH = -1;
  private ArrowDirection arrowDirection;
  private float arrowWidth;
  private float arrowHeight;
  private float arrowPosition;
  private float cornersRadius;
  private Bubble bubble;
  private int bubbleColor;
  private float strokeWidth;
  private int strokeColor;

  /**
   * Creates an instance of bubble layout.
   *
   * @param context The context used to inflate this bubble layout
   */
  public BubbleLayout(Context context) {
    this(context, null, 0);
  }

  /**
   * Creates an instance of bubble layout.
   *
   * @param context The context used to inflate this bubble layout
   * @param attrs   The attribute set to initialise this bubble layout from
   */
  public BubbleLayout(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
  }

  /**
   * Creates an instance of bubble layout.
   *
   * @param context      The context used to inflate this bubble layout
   * @param attrs        The attribute set to initialise this bubble layout from
   * @param defStyleAttr The default style to apply this bubble layout with
   */
  public BubbleLayout(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);

    TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.mapbox_BubbleLayout);
    @ArrowDirection.Value
    int location = a.getInt(R.styleable.mapbox_BubbleLayout_mapbox_bl_arrowDirection,
      ArrowDirection.LEFT);
    arrowDirection = new ArrowDirection(location);
    arrowWidth = a.getDimension(R.styleable.mapbox_BubbleLayout_mapbox_bl_arrowWidth,
      convertDpToPixel(8, context));
    arrowHeight = a.getDimension(R.styleable.mapbox_BubbleLayout_mapbox_bl_arrowHeight,
      convertDpToPixel(8, context));
    arrowPosition = a.getDimension(R.styleable.mapbox_BubbleLayout_mapbox_bl_arrowPosition,
      convertDpToPixel(12, context));
    cornersRadius = a.getDimension(R.styleable.mapbox_BubbleLayout_mapbox_bl_cornersRadius, 0);
    bubbleColor = a.getColor(R.styleable.mapbox_BubbleLayout_mapbox_bl_bubbleColor, Color.WHITE);
    strokeWidth =
      a.getDimension(R.styleable.mapbox_BubbleLayout_mapbox_bl_strokeWidth, DEFAULT_STROKE_WIDTH);
    strokeColor = a.getColor(R.styleable.mapbox_BubbleLayout_mapbox_bl_strokeColor, Color.GRAY);

    a.recycle();
    initPadding();
  }

  @Override
  protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    super.onLayout(changed, left, top, right, bottom);
    initDrawable(0, getWidth(), 0, getHeight());
  }

  @Override
  protected void dispatchDraw(Canvas canvas) {
    if (bubble != null) {
      bubble.draw(canvas);
    }
    super.dispatchDraw(canvas);
  }

  static float convertDpToPixel(float dp, Context context) {
    DisplayMetrics metrics = context.getResources().getDisplayMetrics();
    return dp * (metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT);
  }

  /**
   * Get the arrow direction.
   *
   * @return the arrow direction
   */
  public ArrowDirection getArrowDirection() {
    return arrowDirection;
  }

  /**
   * Set the arrow direction.
   *
   * @param arrowDirection The direction of the arrow
   * @return this
   */
  public BubbleLayout setArrowDirection(ArrowDirection arrowDirection) {
    resetPadding();
    this.arrowDirection = arrowDirection;
    initPadding();
    return this;
  }

  /**
   * Get the arrow width.
   *
   * @return the width of the arrow
   */
  public float getArrowWidth() {
    return arrowWidth;
  }

  /**
   * Set the arrow width.
   *
   * @param arrowWidth The width of the arrow
   * @return this
   */
  public BubbleLayout setArrowWidth(float arrowWidth) {
    resetPadding();
    this.arrowWidth = arrowWidth;
    initPadding();
    return this;
  }

  /**
   * Get the arrow height
   *
   * @return the height of the arrow
   */
  public float getArrowHeight() {
    return arrowHeight;
  }

  /**
   * Set the arrow height.
   *
   * @param arrowHeight The height of the arrow
   * @return this
   */
  public BubbleLayout setArrowHeight(float arrowHeight) {
    resetPadding();
    this.arrowHeight = arrowHeight;
    initPadding();
    return this;
  }

  /**
   * Get the arrow position.
   *
   * @return the arrow position
   */
  public float getArrowPosition() {
    return arrowPosition;
  }

  /**
   * Get the arrow position.
   *
   * @param arrowPosition The arrow position
   * @return this
   */
  public BubbleLayout setArrowPosition(float arrowPosition) {
    resetPadding();
    this.arrowPosition = arrowPosition;
    initPadding();
    return this;
  }

  /**
   * Get the corner radius
   *
   * @return the corner radius
   */
  public float getCornersRadius() {
    return cornersRadius;
  }

  /**
   * Set the corner radius
   *
   * @param cornersRadius The corner radius
   * @return this
   */
  public BubbleLayout setCornersRadius(float cornersRadius) {
    this.cornersRadius = cornersRadius;
    requestLayout();
    return this;
  }

  /**
   * Get the bubble color.
   *
   * @return the bubble color
   */
  public int getBubbleColor() {
    return bubbleColor;
  }

  /**
   * Set the bubble color.
   *
   * @param bubbleColor The buble color
   * @return this
   */
  public BubbleLayout setBubbleColor(int bubbleColor) {
    this.bubbleColor = bubbleColor;
    requestLayout();
    return this;
  }

  /**
   * Get stroke width.
   *
   * @return the stroke width
   */
  public float getStrokeWidth() {
    return strokeWidth;
  }

  /**
   * Set the stroke width.
   *
   * @param strokeWidth The stroke width
   * @return this
   */
  public BubbleLayout setStrokeWidth(float strokeWidth) {
    resetPadding();
    this.strokeWidth = strokeWidth;
    initPadding();
    return this;
  }

  /**
   * Get the stroke color.
   *
   * @return the stroke color
   */
  public int getStrokeColor() {
    return strokeColor;
  }

  /**
   * Set the stroke color.
   *
   * @param strokeColor The stroke color
   * @return this
   */
  public BubbleLayout setStrokeColor(int strokeColor) {
    this.strokeColor = strokeColor;
    requestLayout();
    return this;
  }

  private void initPadding() {
    int paddingLeft = getPaddingLeft();
    int paddingRight = getPaddingRight();
    int paddingTop = getPaddingTop();
    int paddingBottom = getPaddingBottom();
    switch (arrowDirection.getValue()) {
      case ArrowDirection.LEFT:
        paddingLeft += arrowWidth;
        break;
      case ArrowDirection.RIGHT:
        paddingRight += arrowWidth;
        break;
      case ArrowDirection.TOP:
        paddingTop += arrowHeight;
        break;
      case ArrowDirection.BOTTOM:
        paddingBottom += arrowHeight;
        break;
    }
    if (strokeWidth > 0) {
      paddingLeft += strokeWidth;
      paddingRight += strokeWidth;
      paddingTop += strokeWidth;
      paddingBottom += strokeWidth;
    }
    setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
  }

  private void initDrawable(int left, int right, int top, int bottom) {
    if (right < left || bottom < top) {
      return;
    }

    RectF rectF = new RectF(left, top, right, bottom);
    bubble = new Bubble(rectF, arrowDirection, arrowWidth, arrowHeight, arrowPosition, cornersRadius,
      bubbleColor, strokeWidth, strokeColor);
  }

  private void resetPadding() {
    int paddingLeft = getPaddingLeft();
    int paddingRight = getPaddingRight();
    int paddingTop = getPaddingTop();
    int paddingBottom = getPaddingBottom();
    switch (arrowDirection.getValue()) {
      case ArrowDirection.LEFT:
        paddingLeft -= arrowWidth;
        break;
      case ArrowDirection.RIGHT:
        paddingRight -= arrowWidth;
        break;
      case ArrowDirection.TOP:
        paddingTop -= arrowHeight;
        break;
      case ArrowDirection.BOTTOM:
        paddingBottom -= arrowHeight;
        break;
    }
    if (strokeWidth > 0) {
      paddingLeft -= strokeWidth;
      paddingRight -= strokeWidth;
      paddingTop -= strokeWidth;
      paddingBottom -= strokeWidth;
    }
    setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
  }
}