Android-如何使Google Maps显示折线以动画化顺序闪烁的点

时间:2018-12-20 11:52:01

标签: google-maps-markers google-maps-android-api-2

我正在寻找一种使android设备中的Google地图上两个标记之间的点动起来的方法。
所以我最后想要的是两个图像之间的以下行:

enter image description here

,它将像以下典型的Google折线实现一样使用:

enter image description here

让我们说有一个点A和一个点B。如果将用户直接指向点B,则该线会从点A动画到点B,因此用户知道将沿着该方向行走。

要实现这一点,我想我可以从折线中取出点并删除它们,然后再添加回去 迅速地。因此,假设我在polyLine中有5个点,我将删除位置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 :(得分:1)

您可以在this answer中使用基于MapView的自定义视图View Canvas动画:

  

此方法要求   基于MapView   custom view,   实现:

     
      
  • 在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到从点A动画到点B的点C。要获得点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;
    }

}

NB!这只是想法,而不是经过全面测试的代码。