Вы можете использовать пользовательский вид на основе MapView View Canvas animationlike в этот ответ :
Этот подход требует MapView
на основе пользовательский вид , который реализует:
рисование поверх холста MapView;
настройка стилей линий (круги вместо простой линии);
привязка пути к координатам карты широты / долготы
выполнение анимации.
Рисованиеповерх MapView необходимо переопределить dispatchDraw()
.Для настройки стилей линий необходим setPathEffect()
метод класса Paint
, который позволяет создать путь создания для "круговой печати" (в пикселях), которая будет повторяться при каждом "продвижении" (впикселей тоже), примерно так:
mCircleStampPath = new Path ();mCircleStampPath.addCircle (0,0, CIRCLE_RADIUS, Path.Direction.CCW);mCircleStampPath.close ();
Для привязки пути на экране к координатам широты / долготы Projection.toScreenLocation()
требуется, для которого требуется объект GoogleMap
, поэтому пользовательское представление должно реализовыватьOnMapReadyCallback
для получения.Для непрерывной анимации можно использовать postInvalidateDelayed()
.
, но не рисовать траекторию непосредственно из точки A в точку B, а из точки A в точку C, которая анимируется из A в BЧтобы получить текущую позицию точки C, вы можете использовать SphericalUtil.interpolate()
из Google Maps Android API Utility Library .Примерно так:
public class EnhancedMapView extends MapView implements OnMapReadyCallback {
private static final float CIRCLE_RADIUS = 10;
private static final float CIRCLE_ADVANCE = 3.5f * CIRCLE_RADIUS; // spacing between each circle stamp
private static final int FRAMES_PER_SECOND = 30;
private static final int ANIMATION_DURATION = 10000;
private OnMapReadyCallback mMapReadyCallback;
private GoogleMap mGoogleMap;
private LatLng mPointA;
private LatLng mPointB;
private LatLng mPointC;
private float mCirclePhase = 0; // amount to offset before the first circle is stamped
private Path mCircleStampPath;
private Paint mPaintLine;
private final Path mPathFromAtoC = new Path();
private long mStartTime;
private long mElapsedTime;
public EnhancedMapView(@NonNull Context context) {
super(context);
init();
}
public EnhancedMapView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public EnhancedMapView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public EnhancedMapView(@NonNull Context context, @Nullable GoogleMapOptions options) {
super(context, options);
init();
}
@Override
public void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
canvas.save();
drawLineFomAtoB(canvas);
canvas.restore();
// perform one shot animation
mElapsedTime = System.currentTimeMillis() - mStartTime;
if (mElapsedTime < ANIMATION_DURATION) {
postInvalidateDelayed(1000 / FRAMES_PER_SECOND);
}
}
private void drawLineFomAtoB(Canvas canvas) {
if (mGoogleMap == null || mPointA == null || mPointB == null) {
return;
}
// interpolate current position
mPointC = SphericalUtil.interpolate(mPointA, mPointB, (float) mElapsedTime / (float)ANIMATION_DURATION);
final Projection mapProjection = mGoogleMap.getProjection();
final Point pointA = mapProjection.toScreenLocation(mPointA);
final Point pointC = mapProjection.toScreenLocation(mPointC);
mPathFromAtoC.rewind();
mPathFromAtoC.moveTo(pointC.x, pointC.y);
mPathFromAtoC.lineTo(pointA.x, pointA.y);
// change phase for circles shift
mCirclePhase = (mCirclePhase < CIRCLE_ADVANCE)
? mCirclePhase + 1.0f
: 0;
mPaintLine.setPathEffect(new PathDashPathEffect(mCircleStampPath, CIRCLE_ADVANCE, mCirclePhase, PathDashPathEffect.Style.ROTATE));
canvas.drawPath(mPathFromAtoC, mPaintLine);
}
private void init() {
setWillNotDraw(false);
mCircleStampPath = new Path();
mCircleStampPath.addCircle(0,0, CIRCLE_RADIUS, Path.Direction.CCW);
mCircleStampPath.close();
mPaintLine = new Paint();
mPaintLine.setColor(Color.BLACK);
mPaintLine.setStrokeWidth(1);
mPaintLine.setStyle(Paint.Style.STROKE);
mPaintLine.setPathEffect(new PathDashPathEffect(mCircleStampPath, CIRCLE_ADVANCE, mCirclePhase, PathDashPathEffect.Style.ROTATE));
// start animation
mStartTime = System.currentTimeMillis();
postInvalidate();
}
@Override
public void getMapAsync(OnMapReadyCallback callback) {
mMapReadyCallback = callback;
super.getMapAsync(this);
}
@Override
public void onMapReady(GoogleMap googleMap) {
mGoogleMap = googleMap;
mGoogleMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() {
@Override
public void onCameraMove() {
invalidate();
}
});
if (mMapReadyCallback != null) {
mMapReadyCallback.onMapReady(googleMap);
}
}
public void setPoints(LatLng pointA, LatLng pointB) {
mPointA = pointA;
mPointB = pointB;
}
}
Внимание!Это просто идея, а не полностью протестированный код.