summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
authorTobrun <tobrun.van.nuland@gmail.com>2016-06-16 10:58:17 +0200
committerTobrun <tobrun.van.nuland@gmail.com>2016-06-16 16:02:10 +0200
commitdd221596ba6dfa3b8866b69a11d01e918df5af29 (patch)
tree7551b93deb8f781f0d29d66c428fe8b23b005586 /platform
parent8e9fde66083b366e8e7bb5adf8e946b52004f83a (diff)
downloadqtlocation-mapboxgl-dd221596ba6dfa3b8866b69a11d01e918df5af29.tar.gz
[android] #5342 - initial marker animation
Diffstat (limited to 'platform')
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java85
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java135
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java6
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java31
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml7
5 files changed, 218 insertions, 46 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java
index 49d7a061d0..580c3796da 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java
@@ -1,12 +1,16 @@
package com.mapbox.mapboxsdk.annotations;
+import android.animation.AnimatorSet;
import android.graphics.Bitmap;
+import android.graphics.PointF;
import android.support.annotation.FloatRange;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.View;
+import android.view.animation.AnimationUtils;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
+import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapboxMap;
/**
@@ -26,8 +30,8 @@ public class MarkerView extends Marker {
private float anchorU;
private float anchorV;
- private float offsetX;
- private float offsetY;
+ private float offsetX = -1;
+ private float offsetY = -1;
private float infoWindowAnchorU;
private float infoWindowAnchorV;
@@ -43,6 +47,15 @@ public class MarkerView extends Marker {
private boolean selected;
+ private LatLng targetPosition;
+ private boolean shouldAnimate;
+ private boolean isAnimationRunning;
+ private AnimatorSet set;
+
+ private long startTime;
+ private long duration;
+ private long remainingTime;
+
/**
* Publicly hidden default constructor
*/
@@ -279,7 +292,7 @@ public class MarkerView extends Marker {
*
* @param alpha the alpha value to animate to
*/
- public void setAlpha(@FloatRange(from=0.0, to=255.0)float alpha) {
+ public void setAlpha(@FloatRange(from = 0.0, to = 255.0) float alpha) {
this.alpha = alpha;
if (markerViewManager != null) {
markerViewManager.animateAlpha(this, alpha);
@@ -339,6 +352,72 @@ public class MarkerView extends Marker {
markerViewManager = mapboxMap.getMarkerViewManager();
}
+ @Override
+ public void setPosition(LatLng position) {
+ setPosition(position, 0);
+ }
+
+ public void setPosition(LatLng position, long duration) {
+ if (duration <= 0) {
+ // update position instantly
+ super.setPosition(position);
+ if (markerViewManager != null) {
+ markerViewManager.update();
+ }
+ } else {
+ // animate using Android SDK animations
+ this.targetPosition = position;
+ if (markerViewManager != null) {
+ markerViewManager.animatePosition(this, duration);
+ }
+ }
+ }
+
+ boolean shouldAnimate() {
+ return shouldAnimate;
+ }
+
+ void setShouldAnimate(boolean animating) {
+ shouldAnimate = animating;
+ }
+
+ boolean isAnimating() {
+ return isAnimationRunning;
+ }
+
+ void setAnimating(boolean animationRunning) {
+ isAnimationRunning = animationRunning;
+ }
+
+ LatLng getTargetPosition() {
+ return targetPosition;
+ }
+
+ void setAnimation(AnimatorSet set) {
+ this.set = set;
+ }
+
+ AnimatorSet getAnimation() {
+ return set;
+ }
+
+ long getRemainingTime() {
+ long time = duration - (AnimationUtils.currentAnimationTimeMillis() - startTime);
+ return time > 0 ? time : 0;
+ }
+
+ void setDuration(long duration) {
+ this.duration = duration;
+ }
+
+ void setStartTime(long startTime) {
+ this.startTime = startTime;
+ }
+
+ PointF getScreenLocation(@NonNull View convertView) {
+ return new PointF(convertView.getX() + offsetX, convertView.getY() + offsetY);
+ }
+
/**
* Get the String representation of a MarkerView.
*
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java
index f1794b808f..b438e28d96 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java
@@ -1,14 +1,19 @@
package com.mapbox.mapboxsdk.annotations;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.PointF;
+import android.os.CountDownTimer;
import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import android.support.v4.util.Pools;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import com.mapbox.mapboxsdk.R;
@@ -38,6 +43,7 @@ public class MarkerViewManager {
private long viewMarkerBoundsUpdateTime;
private MapboxMap.OnMarkerViewClickListener onMarkerViewClickListener;
private ImageMarkerViewAdapter defaultMarkerViewAdapter;
+ private CountDownTimer timer;
/**
* Creates an instance of MarkerViewManager.
@@ -111,24 +117,60 @@ public class MarkerViewManager {
* </p>
*/
public void update() {
- View convertView;
- for (MarkerView marker : markerViewMap.keySet()) {
- convertView = markerViewMap.get(marker);
+ for (final MarkerView marker : markerViewMap.keySet()) {
+ final View convertView = markerViewMap.get(marker);
if (convertView != null) {
- PointF point = mapboxMap.getProjection().toScreenLocation(marker.getPosition());
- int x = (int) (marker.getAnchorU() * convertView.getMeasuredWidth());
- int y = (int) (marker.getAnchorV() * convertView.getMeasuredHeight());
+ if (marker.isAnimating() || !marker.shouldAnimate()) {
+ if (marker.isAnimating()) {
+ // cancel ongoing animations
+ marker.setAnimating(false);
+ AnimatorSet set = marker.getAnimation();
+ List<Animator> animations = set.getChildAnimations();
+ float x = (Float) ((ObjectAnimator) animations.get(0)).getAnimatedValue();
+ float y = (Float) ((ObjectAnimator) animations.get(1)).getAnimatedValue();
+ PointF pointF = new PointF(x + marker.getOffsetX(), y + marker.getOffsetY());
+ marker.setPosition(mapboxMap.getProjection().fromScreenLocation(pointF));
+ set.cancel();
+ }
+
+ // update position on map
+ PointF point = mapboxMap.getProjection().toScreenLocation(marker.getPosition());
+ if (marker.getOffsetX() == -1) {
+ int x = (int) (marker.getAnchorU() * convertView.getMeasuredWidth());
+ int y = (int) (marker.getAnchorV() * convertView.getMeasuredHeight());
+ marker.setOffsetX(x);
+ marker.setOffsetY(y);
+ }
+
+ convertView.setX(point.x - marker.getOffsetX());
+ convertView.setY(point.y - marker.getOffsetY());
- marker.setOffsetX(x);
- marker.setOffsetY(y);
+ // animate visibility
+ if (marker.isVisible() && convertView.getVisibility() == View.GONE) {
+ convertView.animate().cancel();
+ convertView.setAlpha(0);
+ AnimatorUtils.alpha(convertView, 1);
+ }
+ } else {
+ if (timer == null) {
+ timer = new CountDownTimer(50, 560) {
+ @Override
+ public void onTick(long millisUntilFinished) {
- convertView.setX(point.x - x);
- convertView.setY(point.y - y);
+ }
- if (marker.isVisible() && convertView.getVisibility() == View.GONE) {
- convertView.animate().cancel();
- convertView.setAlpha(0);
- AnimatorUtils.alpha(convertView, 1);
+ @Override
+ public void onFinish() {
+ animate(marker, convertView);
+ }
+ };
+ } else {
+ timer.cancel();
+ PointF point = mapboxMap.getProjection().toScreenLocation(marker.getPosition());
+ convertView.setX(point.x - marker.getOffsetX());
+ convertView.setY(point.y - marker.getOffsetY());
+ }
+ timer.start();
}
}
}
@@ -200,9 +242,10 @@ public class MarkerViewManager {
* <p>
* The {@link com.mapbox.mapboxsdk.maps.MapboxMap.MarkerViewAdapter#onSelect(MarkerView, View, boolean)} will be called to execute an animation.
* </p>
- * @param marker the MarkerView object to select
+ *
+ * @param marker the MarkerView object to select
* @param convertView the View presentation of the MarkerView
- * @param adapter the adapter used to adapt the marker to the convertView
+ * @param adapter the adapter used to adapt the marker to the convertView
*/
public void select(@NonNull MarkerView marker, View convertView, MapboxMap.MarkerViewAdapter adapter) {
if (convertView != null) {
@@ -240,17 +283,23 @@ public class MarkerViewManager {
* @param marker the MarkerView to remove
*/
public void removeMarkerView(MarkerView marker) {
+ boolean isAnimating = marker.isAnimating();
final View viewHolder = markerViewMap.get(marker);
if (viewHolder != null && marker != null) {
for (final MapboxMap.MarkerViewAdapter<?> adapter : markerViewAdapters) {
if (adapter.getMarkerClass().equals(marker.getClass())) {
- if (adapter.prepareViewForReuse(marker, viewHolder)) {
- adapter.releaseView(viewHolder);
+ if (!isAnimating) {
+ if (adapter.prepareViewForReuse(marker, viewHolder)) {
+ adapter.releaseView(viewHolder);
+ }
}
}
}
}
- markerViewMap.remove(marker);
+
+ if (!isAnimating) {
+ markerViewMap.remove(marker);
+ }
}
/**
@@ -324,7 +373,7 @@ public class MarkerViewManager {
Iterator<MarkerView> iterator = markerViewMap.keySet().iterator();
while (iterator.hasNext()) {
MarkerView m = iterator.next();
- if (!markers.contains(m)) {
+ if (!m.shouldAnimate() && !markers.contains(m)) {
// remove marker
convertView = markerViewMap.get(m);
for (MapboxMap.MarkerViewAdapter adapter : markerViewAdapters) {
@@ -396,6 +445,50 @@ public class MarkerViewManager {
}
}
+ public void animatePosition(@NonNull MarkerView marker, long duration) {
+ marker.setDuration(duration);
+ marker.setStartTime(AnimationUtils.currentAnimationTimeMillis());
+ marker.setShouldAnimate(true);
+ animate(marker, markerViewMap.get(marker));
+ }
+
+ private void animate(final MarkerView marker, @Nullable View convertView) {
+ if (convertView != null) {
+ marker.setAnimating(true);
+ PointF screenLocation = mapboxMap.getProjection().toScreenLocation(marker.getTargetPosition());
+ PointF currentLocation = mapboxMap.getProjection().toScreenLocation(marker.getPosition());
+ convertView.setX(currentLocation.x - marker.getOffsetX());
+ convertView.setY(currentLocation.y - marker.getOffsetY());
+ ObjectAnimator animatorX = ObjectAnimator.ofFloat(convertView, "x", screenLocation.x - marker.getOffsetX());
+ ObjectAnimator animatorY = ObjectAnimator.ofFloat(convertView, "y", screenLocation.y - marker.getOffsetY());
+ AnimatorSet set = new AnimatorSet();
+ set.playTogether(animatorX, animatorY);
+ marker.setAnimation(set);
+ set.setDuration(marker.getRemainingTime());
+ set.addListener(new AnimatorListenerAdapter() {
+
+ private boolean canceled;
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ super.onAnimationCancel(animation);
+ canceled = true;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ if (!canceled) {
+ marker.setShouldAnimate(false);
+ marker.setPosition(marker.getTargetPosition());
+ }
+ }
+ });
+ marker.setAnimation(set);
+ set.start();
+ }
+ }
+
/**
* Default MarkerViewAdapter used for base class of MarkerView to adapt a MarkerView to an ImageView
*/
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
index ae71ee384a..8fe9568eaa 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
@@ -1398,8 +1398,12 @@ public class MapView extends FrameLayout {
mCompassView.update(getDirection());
mMyLocationView.update();
- mMapboxMap.getMarkerViewManager().update();
+ try {
+ mMapboxMap.getMarkerViewManager().update();
+ }catch (NullPointerException e){
+
+ }
for (InfoWindow infoWindow : mMapboxMap.getInfoWindows()) {
infoWindow.update();
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java
index 1e15c9ea36..bbd7428ead 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java
@@ -1,18 +1,17 @@
package com.mapbox.mapboxsdk.testapp.activity.annotation;
import android.animation.TypeEvaluator;
-import android.animation.ValueAnimator;
import android.os.Bundle;
+import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import com.mapbox.mapboxsdk.annotations.Marker;
-import com.mapbox.mapboxsdk.annotations.MarkerOptions;
+import com.mapbox.mapboxsdk.annotations.MarkerView;
+import com.mapbox.mapboxsdk.annotations.MarkerViewOptions;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
@@ -42,24 +41,18 @@ public class AnimatedMarkerActivity extends AppCompatActivity {
mMapView.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(@NonNull final MapboxMap mapboxMap) {
+
LatLng brussels = new LatLng(50.900446, 4.485251);
- LatLng washington = new LatLng(38.897108, -77.036716);
-
- final Marker marker = mapboxMap.addMarker(new MarkerOptions().position(brussels));
- ValueAnimator markerAnimator = ValueAnimator.ofObject(new LatLngEvaluator(), (Object[]) new LatLng[]{brussels, washington});
- markerAnimator.setDuration(5000);
- markerAnimator.setRepeatCount(ValueAnimator.INFINITE);
- markerAnimator.setRepeatMode(ValueAnimator.REVERSE);
- markerAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
- markerAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ final MarkerView marker = mapboxMap.addMarker(new MarkerViewOptions().position(brussels));
+
+ // FIXME workaround because view is not actually added at this time
+ final LatLng utrecht = new LatLng(52.086224, 5.122309);
+ new Handler().postDelayed(new Runnable() {
@Override
- public void onAnimationUpdate(ValueAnimator animation) {
- if (marker != null) {
- marker.setPosition((LatLng) animation.getAnimatedValue());
- }
+ public void run() {
+ marker.setPosition(utrecht, 6500l /*animation duration*/);
}
- });
- markerAnimator.start();
+ }, 1000);
}
});
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml
index 8c025d999c..b9bfa701a8 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
- xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
@@ -16,7 +16,10 @@
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_below="@id/toolbar"
+ app:center_latitude="51.502615"
+ app:center_longitude="4.972326"
app:style_url="@string/style_light"
- android:layout_below="@id/toolbar" />
+ app:zoom="6" />
</RelativeLayout>