diff options
author | Tobrun <tobrun.van.nuland@gmail.com> | 2016-06-16 10:58:17 +0200 |
---|---|---|
committer | Tobrun <tobrun.van.nuland@gmail.com> | 2016-06-16 16:02:10 +0200 |
commit | dd221596ba6dfa3b8866b69a11d01e918df5af29 (patch) | |
tree | 7551b93deb8f781f0d29d66c428fe8b23b005586 /platform/android | |
parent | 8e9fde66083b366e8e7bb5adf8e946b52004f83a (diff) | |
download | qtlocation-mapboxgl-dd221596ba6dfa3b8866b69a11d01e918df5af29.tar.gz |
[android] #5342 - initial marker animation
Diffstat (limited to 'platform/android')
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> |