7
7
import android .graphics .drawable .Drawable ;
8
8
import android .os .PowerManager ;
9
9
import android .util .DisplayMetrics ;
10
+ import android .view .DragEvent ;
10
11
import android .view .MotionEvent ;
12
+ import android .view .View ;
11
13
12
14
import androidx .core .content .res .ResourcesCompat ;
13
15
30
32
import org .osmdroid .views .overlay .mylocation .MyLocationNewOverlay ;
31
33
32
34
import java .io .File ;
33
- import java .util .ArrayList ;
34
35
import java .util .List ;
35
- import java .util .stream .Collectors ;
36
36
37
37
import de .hauke_stieler .geonotes .database .Database ;
38
38
import de .hauke_stieler .geonotes .R ;
@@ -50,7 +50,6 @@ public class Map {
50
50
51
51
private MarkerWindow markerInfoWindow ;
52
52
private Marker .OnMarkerClickListener markerClickListener ;
53
- private Marker markerToMove ;
54
53
55
54
private final Drawable normalIcon ;
56
55
private final Drawable normalWithPhotoIcon ;
@@ -59,6 +58,10 @@ public class Map {
59
58
60
59
private boolean snapNoteToGps ;
61
60
61
+ // Variables used during moving a marker. Do not use when no marker is currently in move mode (aka when markerToMove==null)
62
+ private Marker markerToMove ;
63
+ private Point dragStartMarkerPosition ;
64
+
62
65
public Map (Context context ,
63
66
MapView map ,
64
67
Database database ) {
@@ -121,43 +124,23 @@ private void createOverlays(Context context, MapView map, BitmapDrawable locatio
121
124
122
125
// Add marker click listener. Will be called when the user clicks/taps on a marker.
123
126
markerClickListener = (marker , mapView ) -> {
124
- // When we are in the state of moving an existing marker, we do not want to interact with other markers -> simply return
125
- if (markerToMove != null ) {
126
- return true ;
127
- }
128
-
129
127
selectMarker (marker );
130
-
131
128
return true ;
132
129
};
133
130
134
131
// React to touches on the map
135
132
MapEventsReceiver mapEventsReceiver = new MapEventsReceiver () {
136
133
@ Override
137
134
public boolean singleTapConfirmedHelper (GeoPoint p ) {
138
- // When we have a marker to move, set its new position, store that and disable move-state
139
- if (markerToMove != null ) {
140
- markerToMove .setPosition (p );
141
- selectMarker (markerToMove );
142
-
143
- // If the ID is set, the marker exists in the DB, therefore we store that new location
144
- String id = markerToMove .getId ();
145
- if (id != null ) {
146
- database .updateLocation (Long .parseLong (id ), p );
147
- }
148
-
149
- markerToMove = null ;
135
+ // No marker to move here -> deselect or create marker
136
+ // (selecting marker on the map is handles via the separate markerClickListener)
137
+ if (markerInfoWindow .getSelectedMarker () != null ) {
138
+ // Deselect selected marker:
139
+ setNormalIcon (markerInfoWindow .getSelectedMarker ());
140
+ markerInfoWindow .close ();
150
141
} else {
151
- // No marker to move here -> deselect or create marker
152
- // (selecting marker on the map is handles via the separate markerClickListener)
153
- if (markerInfoWindow .getSelectedMarker () != null ) {
154
- // Deselect selected marker:
155
- setNormalIcon (markerInfoWindow .getSelectedMarker ());
156
- markerInfoWindow .close ();
157
- } else {
158
- // No marker currently selected -> create new marker at this location
159
- initAndSelectMarker (p );
160
- }
142
+ // No marker currently selected -> create new marker at this location
143
+ initAndSelectMarker (p );
161
144
}
162
145
163
146
return false ;
@@ -175,8 +158,35 @@ public boolean longPressHelper(GeoPoint p) {
175
158
public void addMapListener (MapListener listener , TouchDownListener touchDownListener ) {
176
159
map .addMapListener (listener );
177
160
map .setOnTouchListener ((v , event ) -> {
178
- if (event .getAction () == MotionEvent .ACTION_DOWN ) {
179
- touchDownListener .onTouchDown ();
161
+ switch (event .getAction ()) {
162
+ case MotionEvent .ACTION_DOWN :
163
+ touchDownListener .onTouchDown ();
164
+
165
+ // Initialize movement of the marker: Store current screen-location to keep marker there
166
+ if (markerToMove != null ) {
167
+ dragStartMarkerPosition = map .getProjection ().toPixels (markerToMove .getPosition (), null );
168
+ }
169
+ break ;
170
+ case MotionEvent .ACTION_MOVE :
171
+ // When in drag-mode: Keep marker at original screen location by setting its position
172
+ if (markerToMove != null && dragStartMarkerPosition != null ) {
173
+ markerToMove .setPosition ((GeoPoint ) map .getProjection ().fromPixels (dragStartMarkerPosition .x , dragStartMarkerPosition .y ));
174
+ }
175
+ break ;
176
+ case MotionEvent .ACTION_UP :
177
+ if (markerToMove != null ) {
178
+ selectMarker (markerToMove );
179
+
180
+ // If the ID is set, the marker exists in the DB, therefore we store that new location
181
+ String id = markerToMove .getId ();
182
+ if (id != null ) {
183
+ database .updateLocation (Long .parseLong (id ), markerToMove .getPosition ());
184
+ }
185
+
186
+ dragStartMarkerPosition = null ;
187
+ markerToMove = null ;
188
+ }
189
+ break ;
180
190
}
181
191
return false ;
182
192
});
@@ -203,7 +213,14 @@ public void onSave(Marker marker) {
203
213
@ Override
204
214
public void onMove (Marker marker ) {
205
215
markerToMove = marker ;
206
- // The new position is determined and stored in the click handler of the map
216
+ // The new position is determined and stored in the onTouch-handler of the map
217
+ }
218
+
219
+ @ Override
220
+ public void onTextChanged () {
221
+ if (getSelectedMarker () != null ) {
222
+ moveMapWithMarkerWindowOnTop (getSelectedMarker ());
223
+ }
207
224
}
208
225
});
209
226
}
@@ -272,7 +289,40 @@ private void selectMarker(Marker marker) {
272
289
273
290
addImagesToMarkerWindow ();
274
291
275
- zoomToLocation (marker .getPosition (), map .getZoomLevelDouble ());
292
+ // Fragment not yet drawn, so we have to measure the height manually
293
+ markerInfoWindow .getView ().measure (View .MeasureSpec .UNSPECIFIED , View .MeasureSpec .UNSPECIFIED );
294
+ moveMapWithMarkerWindowOnTop (marker );
295
+ }
296
+
297
+ private void moveMapWithMarkerWindowOnTop (Marker marker ) {
298
+ int markerWindowHeight = markerInfoWindow .getView ().getMeasuredHeight ();
299
+
300
+ Point markerPositionPixel = new Point ();
301
+ map .getProjection ().toPixels (marker .getPosition (), markerPositionPixel );
302
+
303
+ /*
304
+ * Center of the screen in relation to the y-coordinate of the marker such that the window
305
+ * is 20px below the top-edge of the map.
306
+ * _________________
307
+ * | ___________ |
308
+ * | |___________| |
309
+ * | |_| | _ --> markerPositionPixel.y
310
+ * | | |
311
+ * | | |- distance we have to add to markerPositionPixel.y
312
+ * | | _|
313
+ * | X | --> center of the screen = Y-coordinate we need to find
314
+ * | |
315
+ * | |
316
+ * | |
317
+ * | |
318
+ * |_________________|
319
+ */
320
+ int yCoordinate = markerPositionPixel .y + (map .getHeight () / 2 - markerWindowHeight - marker .getIcon ().getIntrinsicHeight () - 20 );
321
+
322
+ Point locationInPixels = new Point (markerPositionPixel .x , yCoordinate );
323
+ IGeoPoint newPoint = map .getProjection ().fromPixels (locationInPixels .x , locationInPixels .y );
324
+
325
+ zoomToLocation (newPoint , map .getZoomLevelDouble ());
276
326
}
277
327
278
328
private Marker getSelectedMarker () {
@@ -326,12 +376,8 @@ public void setMapScaleFactor(float factor) {
326
376
map .setTilesScaleFactor (factor );
327
377
}
328
378
329
- private void zoomToLocation (GeoPoint p , double zoom ) {
330
- Point locationInPixels = new Point ();
331
- map .getProjection ().toPixels (p , locationInPixels );
332
- IGeoPoint newPoint = map .getProjection ().fromPixels (locationInPixels .x , locationInPixels .y );
333
-
334
- mapController .setCenter (newPoint );
379
+ private void zoomToLocation (IGeoPoint p , double zoom ) {
380
+ mapController .setCenter (new GeoPoint (p ));
335
381
mapController .setZoom (zoom );
336
382
}
337
383
0 commit comments