Android - Как заставить Google Maps отображать ломаную линию, которая анимирует последовательные мигающие точки - PullRequest
0 голосов
/ 20 декабря 2018

Я ищу способ анимировать точки между двумя маркерами на карте Google в Android-устройстве.
Итак, в итоге я хочу следующую строку между двумя изображениями:

enter image description here

, и это будет использоваться как эта типичная реализация полилинии Google:

enter image description here

скажем, тамэто точка A и точка B. Если я направляю пользователя в точку B, то линия анимируется из точки A в точку B, поэтому пользователь знает, как идти в этом направлении.

Для достижения этой цели я подумалЯ мог бы получить точки из PolyLine, удалить их и быстро добавить обратно.Допустим, у меня было 5 точек в PolyLine, я удалил бы позицию 1, затем вернул ее, затем удалил позицию 2 и вернул ее назад, чтобы смоделировать эту анимацию.

, но она не работает.После установки полилинии кажется, что я не могу ее изменить.у вас есть какие-либо предложения?

val dotPattern = Arrays.asList(Dot(), Gap(convertDpToPixel(7).toFloat()))
            val polyLineOptions: PolylineOptions = PolylineOptions()
                    .add(usersLocation)
                    .add(users_destination)
                    .pattern(dotPattern)
                    .width(convertDpToPixel(6).toFloat())
            dottedPolyLine = googleMap.addPolyline(polyLineOptions)

dottedPolyLine? .points? .removeAt (1) // здесь в качестве теста, если моя идея, я пытаюсь удалить точку, но похоже, что точка здесь означает текущее местоположение или пункт назначениятак что всегда 2. я думал, что точка будет одной из точек.

1 Ответ

0 голосов
/ 27 декабря 2018

Вы можете использовать пользовательский вид на основе 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;
    }

}

Внимание!Это просто идея, а не полностью протестированный код.

...