diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java index cc44ac97155..c8c5c6bd37c 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java @@ -5,13 +5,20 @@ import android.animation.TypeEvaluator; import android.animation.ValueAnimator; import android.os.Bundle; +import android.support.v4.util.LongSparseArray; import android.support.v4.view.animation.FastOutLinearInInterpolator; import android.support.v4.view.animation.FastOutSlowInInterpolator; +import android.support.v4.view.animation.PathInterpolatorCompat; import android.support.v7.app.AppCompatActivity; +import android.view.Menu; +import android.view.MenuItem; import android.view.View; import android.view.animation.AnticipateOvershootInterpolator; +import android.view.animation.BounceInterpolator; +import android.view.animation.Interpolator; import com.mapbox.mapboxsdk.camera.CameraPosition; +import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; @@ -24,6 +31,51 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapReadyCallback { private static final double ANIMATION_DELAY_FACTOR = 1.5; + private static final LatLng START_LAT_LNG = new LatLng(37.787947, -122.407432); + + private final LongSparseArray animators = new LongSparseArray() { + { + put(R.id.menu_action_accelerate_decelerate_interpolator, new AnimatorBuilder() { + @Override + public Animator build() { + AnimatorSet animatorSet = new AnimatorSet(); + animatorSet.playTogether( + createLatLngAnimator(START_LAT_LNG, new LatLng(37.826715, -122.422795)), + obtainExampleInterpolator(new FastOutSlowInInterpolator(), 2500) + ); + return animatorSet; + } + }); + + put(R.id.menu_action_bounce_interpolator, new AnimatorBuilder() { + @Override + public Animator build() { + AnimatorSet animatorSet = new AnimatorSet(); + animatorSet.playTogether( + createLatLngAnimator(START_LAT_LNG, new LatLng(37.787947, -122.407432)), + obtainExampleInterpolator(new BounceInterpolator(), 3750) + ); + return animatorSet; + } + }); + + put(R.id.menu_action_anticipate_overshoot_interpolator, new AnimatorBuilder() { + @Override + public Animator build() { + return obtainExampleInterpolator(new AnticipateOvershootInterpolator(), 2500); + } + }); + + put(R.id.menu_action_path_interpolator, new AnimatorBuilder() { + @Override + public Animator build() { + return obtainExampleInterpolator( + PathInterpolatorCompat.create(.22f, .68f, 0, 1.71f), 2500); + } + }); + } + }; + private MapView mapView; private MapboxMap mapboxMap; @@ -32,7 +84,6 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapRe protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_camera_animator); - mapView = (MapView) findViewById(R.id.mapView); if (mapView != null) { mapView.onCreate(savedInstanceState); @@ -43,27 +94,42 @@ protected void onCreate(Bundle savedInstanceState) { @Override public void onMapReady(final MapboxMap map) { mapboxMap = map; + initFab(); + } + + private void initFab() { findViewById(R.id.fab).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { view.setVisibility(View.GONE); - createAnimator(mapboxMap.getCameraPosition()).start(); + + CameraPosition animatedPosition = new CameraPosition.Builder() + .target(new LatLng(37.789992, -122.402214)) + .tilt(60) + .zoom(14.5f) + .bearing(135) + .build(); + + createExampleAnimator(mapboxMap.getCameraPosition(), animatedPosition).start(); } }); } - private Animator createAnimator(CameraPosition currentPosition) { + // + // Animator API used for the animation on the FAB + // + + private Animator createExampleAnimator(CameraPosition currentPosition, CameraPosition targetPosition) { AnimatorSet animatorSet = new AnimatorSet(); - animatorSet.play(createLatLngAnimator(currentPosition.target)); - animatorSet.play(createZoomAnimator(currentPosition.zoom)); - animatorSet.play(createBearingAnimator(currentPosition.bearing)); - animatorSet.play(createTiltAnimator(currentPosition.tilt)); + animatorSet.play(createLatLngAnimator(currentPosition.target, targetPosition.target)); + animatorSet.play(createZoomAnimator(currentPosition.zoom, targetPosition.zoom)); + animatorSet.play(createBearingAnimator(currentPosition.bearing, targetPosition.bearing)); + animatorSet.play(createTiltAnimator(currentPosition.tilt, targetPosition.tilt)); return animatorSet; } - private Animator createLatLngAnimator(LatLng currentPosition) { - LatLng target = new LatLng(37.789992, -122.402214); - ValueAnimator latLngAnimator = ValueAnimator.ofObject(new LatLngEvaluator(), currentPosition, target); + private Animator createLatLngAnimator(LatLng currentPosition, LatLng targetPosition) { + ValueAnimator latLngAnimator = ValueAnimator.ofObject(new LatLngEvaluator(), currentPosition, targetPosition); latLngAnimator.setDuration((long) (1000 * ANIMATION_DELAY_FACTOR)); latLngAnimator.setInterpolator(new FastOutSlowInInterpolator()); latLngAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @@ -75,8 +141,8 @@ public void onAnimationUpdate(ValueAnimator animation) { return latLngAnimator; } - private Animator createZoomAnimator(double currentZoom) { - ValueAnimator zoomAnimator = ValueAnimator.ofFloat((float) currentZoom, 14.5f); + private Animator createZoomAnimator(double currentZoom, double targetZoom) { + ValueAnimator zoomAnimator = ValueAnimator.ofFloat((float) currentZoom, (float) targetZoom); zoomAnimator.setDuration((long) (2200 * ANIMATION_DELAY_FACTOR)); zoomAnimator.setStartDelay((long) (600 * ANIMATION_DELAY_FACTOR)); zoomAnimator.setInterpolator(new AnticipateOvershootInterpolator()); @@ -89,8 +155,8 @@ public void onAnimationUpdate(ValueAnimator animation) { return zoomAnimator; } - private Animator createBearingAnimator(double currentBearing) { - ValueAnimator bearingAnimator = ValueAnimator.ofFloat((float) currentBearing, 135); + private Animator createBearingAnimator(double currentBearing, double targetBearing) { + ValueAnimator bearingAnimator = ValueAnimator.ofFloat((float) currentBearing, (float) targetBearing); bearingAnimator.setDuration((long) (1000 * ANIMATION_DELAY_FACTOR)); bearingAnimator.setStartDelay((long) (1000 * ANIMATION_DELAY_FACTOR)); bearingAnimator.setInterpolator(new FastOutLinearInInterpolator()); @@ -103,8 +169,8 @@ public void onAnimationUpdate(ValueAnimator animation) { return bearingAnimator; } - private Animator createTiltAnimator(double currentTilt) { - ValueAnimator tiltAnimator = ValueAnimator.ofFloat((float) currentTilt, 60); + private Animator createTiltAnimator(double currentTilt, double targetTilt) { + ValueAnimator tiltAnimator = ValueAnimator.ofFloat((float) currentTilt, (float) targetTilt); tiltAnimator.setDuration((long) (1000 * ANIMATION_DELAY_FACTOR)); tiltAnimator.setStartDelay((long) (1500 * ANIMATION_DELAY_FACTOR)); tiltAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @@ -116,20 +182,66 @@ public void onAnimationUpdate(ValueAnimator animation) { return tiltAnimator; } - private static class LatLngEvaluator implements TypeEvaluator { + // + // Interpolator examples + // - private final LatLng latLng = new LatLng(); + private Animator obtainExampleInterpolator(int menuItemId) { + return animators.get(menuItemId).build(); + } - @Override - public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) { - latLng.setLatitude(startValue.getLatitude() - + ((endValue.getLatitude() - startValue.getLatitude()) * fraction)); - latLng.setLongitude(startValue.getLongitude() - + ((endValue.getLongitude() - startValue.getLongitude()) * fraction)); - return latLng; + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_animator, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (mapboxMap == null) { + return false; } + findViewById(R.id.fab).setVisibility(View.GONE); + resetCameraPosition(); + playAnimation(item.getItemId()); + return super.onOptionsItemSelected(item); } + private void resetCameraPosition() { + mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition( + new CameraPosition.Builder() + .target(START_LAT_LNG) + .zoom(11) + .bearing(0) + .tilt(0) + .build() + )); + } + + private void playAnimation(int itemId) { + Animator animator = obtainExampleInterpolator(itemId); + if (animator != null) { + animator.start(); + } + } + + private Animator obtainExampleInterpolator(Interpolator interpolator, long duration) { + ValueAnimator zoomAnimator = ValueAnimator.ofFloat(11.0f, 16.0f); + zoomAnimator.setDuration((long) (duration * ANIMATION_DELAY_FACTOR)); + zoomAnimator.setInterpolator(interpolator); + zoomAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + mapboxMap.setZoom((Float) animation.getAnimatedValue()); + } + }); + return zoomAnimator; + } + + // + // MapView lifecycle + // + @Override protected void onStart() { super.onStart(); @@ -171,4 +283,25 @@ public void onLowMemory() { super.onLowMemory(); mapView.onLowMemory(); } + + /** + * Helper class to evaluate LatLng objects with a ValueAnimator + */ + private static class LatLngEvaluator implements TypeEvaluator { + + private final LatLng latLng = new LatLng(); + + @Override + public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) { + latLng.setLatitude(startValue.getLatitude() + + ((endValue.getLatitude() - startValue.getLatitude()) * fraction)); + latLng.setLongitude(startValue.getLongitude() + + ((endValue.getLongitude() - startValue.getLongitude()) * fraction)); + return latLng; + } + } + + interface AnimatorBuilder { + Animator build(); + } } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_animator.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_animator.xml index d4933bfb9a6..cb14aab91fa 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_animator.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_animator.xml @@ -10,8 +10,8 @@ android:id="@id/mapView" android:layout_width="match_parent" android:layout_height="match_parent" - app:mapbox_cameraTargetLat="37.774913" - app:mapbox_cameraTargetLng="-122.419368" + app:mapbox_cameraTargetLat="37.787947" + app:mapbox_cameraTargetLng="-122.407432" app:mapbox_cameraZoom="11" app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"/> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_animator.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_animator.xml new file mode 100644 index 00000000000..db5a62d2cb3 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_animator.xml @@ -0,0 +1,20 @@ + + + + + + + diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/actions.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/actions.xml index 4ca19def710..416b9a8f869 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/actions.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/actions.xml @@ -12,6 +12,10 @@ Reset location source to null Toggle icon overlap Change location + Accelerate/Decelerate interpolator + Bounce interpolator + Anticipate/Overshoot interpolator + PathInterpolator interpolator Move Ease Animate