Насколько я знаю, Google Map Marker и InfoWindow нарисованы на карте в виде плоского растрового изображения. Таким образом, вы не можете выполнять анимацию, взаимодействие с компонентами или даже рисовать тень вокруг них.
Приложение Uber использует другой слой, расположенный поверх карты (вы можете попробовать сделать жест на карте и увидеть, что маркер перемещается, но с небольшой задержкой). Это не легко, потому что вы должны уловить жест каждой карты и соответственно анимировать вид наложения. Я пробовал это раньше, но это слишком много работы, поэтому я оставил это позади.
Ваш импульсный эффект может быть достигнут с помощью Circle
с ValueAnimator
private @ColorInt int mPulseEffectColor;
private int[] mPulseEffectColorElements;
private ValueAnimator mPulseEffectAnimator;
private Circle mPulseCircle;
private void initPulseEffect() {
mPulseEffectColor = ContextCompat.getColor(mContext, R.color.pink);
mPulseEffectColorElements = new int[] {
Color.red(mPulseEffectColor),
Color.green(mPulseEffectColor),
Color.blue(mPulseEffectColor)
};
mPulseEffectAnimator = ValueAnimator.ofFloat(0, calculatePulseRadius(current_map_zoom_level));
mPulseEffectAnimator.setStartDelay(3000);
mPulseEffectAnimator.setDuration(400);
mPulseEffectAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
}
Рассчитать радиус на основе уровня масштабирования карты
private static float calculatePulseRadius(float zoomLevel) {
return (float) Math.pow(2, 16 - zoomLevel) * 160;
}
Регистрация OnCameraIdleListener
для прослушивания измененного масштаба карты
@Override
public void onCameraIdle() {
CameraPosition cameraPosition = mMap.getCameraPosition();
if (mPulseEffectAnimator != null)
mPulseEffectAnimator.setFloatValues(0, calculatePulseRadius(cameraPosition.zoom));
}
Запустить анимацию
private void startPulseAnimation() {
if (mPulseCircle != null)
mPulseCircle.remove();
if (mPulseEffectAnimator != null) {
mPulseEffectAnimator.removeAllUpdateListeners();
mPulseEffectAnimator.removeAllListeners();
mPulseEffectAnimator.end();
}
if (your_marker_coordinate != null) {
mPulseCircle = mMap.addCircle(new CircleOptions()
.center(your_marker_coordinate)
.radius(0).strokeWidth(0)
.fillColor(mPulseEffectColor));
mPulseEffectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
if (mPulseCircle == null)
return;
int alpha = (int) ((1 - valueAnimator.getAnimatedFraction()) * 128);
mPulseCircle.setFillColor(Color.argb(alpha,
mPulseEffectColorElements[0], mPulseEffectColorElements[1], mPulseEffectColorElements[2]));
mPulseCircle.setRadius((float) valueAnimator.getAnimatedValue());
}
});
mPulseEffectAnimator.addListener(new AnimatorListenerAdapter {
@Override
public void onAnimationEnd(Animator animation) {
mPulseEffectAnimator.setStartDelay(2000);
mPulseEffectAnimator.start();
}
});
mPulseEffectAnimator.start();
}
}
Пояснение:
- Используйте
calculatePulseRadius
для пересчета базы радиуса на уровне масштабирования карты, поскольку радиус круга измеряется расстоянием реального мира.
- Используйте
int[] mPulseEffectColorElements
, чтобы сохранить r, g, b цвета круга, чтобы мне не нужно было воссоздавать цвет в каждом кадре. Я только хочу изменить альфа-значение
- Прослушайте конец Аниматора и запустите его снова с задержкой.
Этот код применяется только для 1 круга за раз, несколько кругов требуют более сложной работы, но с одинаковой логикой.
Результат: