[android] #5342 - initial marker animation

This commit is contained in:
Tobrun
2016-06-16 10:58:17 +02:00
parent 8e9fde6608
commit dd221596ba
5 changed files with 218 additions and 46 deletions

View File

@@ -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.
*

View File

@@ -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
*/

View File

@@ -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();
}