[android] #5342 - initial marker animation
This commit is contained in:
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
marker.setOffsetX(x);
|
||||
marker.setOffsetY(y);
|
||||
// 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 - x);
|
||||
convertView.setY(point.y - y);
|
||||
convertView.setX(point.x - marker.getOffsetX());
|
||||
convertView.setY(point.y - marker.getOffsetY());
|
||||
|
||||
if (marker.isVisible() && convertView.getVisibility() == View.GONE) {
|
||||
convertView.animate().cancel();
|
||||
convertView.setAlpha(0);
|
||||
AnimatorUtils.alpha(convertView, 1);
|
||||
// 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) {
|
||||
|
||||
}
|
||||
|
||||
@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
|
||||
*/
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user