【问题标题】:Animate camera to position and set panning in google maps动画相机在谷歌地图中定位和设置平移
【发布时间】:2018-09-10 16:36:01
【问题描述】:

我正在尝试实现类似于谷歌地图导航的工作方式,请查看下图以供参考。在谷歌地图中,​​标记看起来是在一个静态位置,除了相机正在改变


为了实现这一点,我会在每次位置变化时为标记设置动画,然后通过在 Y 坐标中平移 -300 像素将其定位到屏幕底部。

但我无法为相机设置动画以更改位置并同时将屏幕向下移动 300 像素。

当我为相机设置动画以改变位置时,标记准确地移动到屏幕的中心,然后当我将相机移动到低于 300 像素的位置时,其他动画就会发生,这看起来很烦人。

有什么方法可以实现谷歌地图的功能吗?任何参考或帮助表示赞赏。

【问题讨论】:

  • 一种方法是使用当前缩放级别的 Projection.getVisibleRegion() 计算“阴影”目标 - 这将为您提供屏幕像素到 wgs84 空间的当前映射。有了这个,您可以获取新的位置位置,将阴影目标(屏幕的结果中心)计算为像素偏移量(如您所说的 300 像素),并将该像素坐标重新映射到动画目标的 lat/lng。请注意,您的 300px 偏移量是特定于缩放的。 (这并不像我说的那么难 - 只需探索 Projection 类 (getVisibleRegion),它就应该开始有意义了。)
  • 感谢您的快速响应,但我们如何处理轴承?例如。我的相机当前指向东方,而新位置恰好在北方,改变相机方向会导致 LatLng 错误。
  • 我会推荐一个第三方地图服务,您可以根据自己的要求进行定制。 mapbox.com ,看一下代码,你只需要添加几行代码就可以达到预期的效果。

标签: android google-maps animation maps


【解决方案1】:

代码完全在onLocationChanged 中实现,但据记载,其中一些可以在初始化期间提取。

基本上所做的是,使用从屏幕像素偏移导出的距离从当前位置计算阴影目标,使用从最后位置计算的方位推断。

在屏幕录像(下图)中,绿色圆圈代表当前位置(也由地图位置点表示),蓝色圆圈代表阴影目标,由于是地图动画的目标。

下面是概念图:

还有代码(下面有录屏):

@Override
public void onLocationChanged(Location location) {

    // First point processing
    if (lastLocation == null) {

        // save last location
        lastLocation = location;

        // initial camera
        CameraPosition.Builder b = CameraPosition.builder().
                zoom(15.0F).
                target(new LatLng(lastLocation.getLatitude(), lastLocation.getLongitude()));
        CameraUpdate cu = CameraUpdateFactory.newCameraPosition(b.build());
        mMap.animateCamera(cu);
        return;
    }

    // subsequent updates

    LatLng oldPos = new LatLng(lastLocation.getLatitude(), lastLocation.getLongitude());
    LatLng newPos = new LatLng(location.getLatitude(), location.getLongitude());

    // ignore very small position deviations (prevents wild swinging)
    double d = SphericalUtil.computeDistanceBetween(oldPos, newPos);
    if (d < 10) {
        return;
    }


    // compute our own bearing (do not use location bearing)
    double bearing = SphericalUtil.computeHeading(oldPos, newPos);

    //-----------------------------------------------
    // Next section really only needs to be done once

    // Compute distance of pixels on screen using some desirable "offset"

    Projection p = mMap.getProjection();
    Point  bottomRightPoint = p.toScreenLocation(p.getVisibleRegion().nearRight);
    Point center = new Point(bottomRightPoint.x/2,bottomRightPoint.y/2);
    Point offset = new Point(center.x, (center.y + 300));

    LatLng centerLoc = p.fromScreenLocation(center);
    LatLng offsetNewLoc = p.fromScreenLocation(offset);

    // this computed value only changes on zoom
    double offsetDistance = SphericalUtil.computeDistanceBetween(centerLoc, offsetNewLoc);
    //-----------------------------------------------


    // Compute shadow target position from current position (see diagram)
    LatLng shadowTgt = SphericalUtil.computeOffset(newPos,offsetDistance,bearing);

    // update circles
    if (centerCircle != null) {
        centerCircle.setCenter(shadowTgt);
    } else {
        centerCircle = mMap.addCircle(new CircleOptions().strokeColor(Color.BLUE).center(shadowTgt).radius(50));
    }
    if (carCircle != null) {
        carCircle.setCenter(newPos);
    } else {
        carCircle = mMap.addCircle(new CircleOptions().strokeColor(Color.GREEN).center(newPos).radius(50));
    }


    // update camera

    CameraPosition.Builder b = CameraPosition.builder();
    b.zoom(15.0F);
    b.bearing((float)(bearing));
    b.target(shadowTgt);
    CameraUpdate cu = CameraUpdateFactory.newCameraPosition(b.build());
    mMap.animateCamera(cu);

    // save location as last for next update
    lastLocation = location;
}

注意事项:

  • 当缩放改变时,offsetDistance 需要重新计算。 (但如前所述,不需要每次更改位置都这样做。)
  • 轴承在概念图中显示为 0-360,但实际上是 -180-180。
  • 如您所见,大部分工作都是在 SphericalUtil 类中完成的。

【讨论】:

  • 很棒的插图@Andy。只是对一些事情感到好奇。 centerCircle 和 carCircle 的类型是什么?它们是标记吗?实际上在我的源代码中我有一个代表车辆的标记。所以如果这些圆圈与标记相同,那么我可以使用它们吗?
  • @AliAkram 圆圈可以被标记替换,因为它们都有位置并且都可以更新。圆圈用于更有效的演示。例如,可以在绿色圆圈内看到蓝色的“我的位置”标记。
  • 感谢@andy 的回复。绿圈代表什么?
  • 嗨@Andy 我正在像这样为我的信息窗口设置动画,但有时它会超过标记。请提出一些解决方案。谢谢 if (startPosition == null) { startPosition = endPosition; } else if (endPosition == null) { endPosition = startPosition; } 双角 = SphericalUtil.computeHeading(startPosition, endPosition) + 45;双 x = Math.sin(-角度 * Math.PI / 180) * 0.5 + 0.5;双 y = -(Math.cos(-angle * Math.PI / 180) * 0.5 - 0.5); marker.setInfoWindowAnchor((float) x, (float) y);
  • @AliAkram - 信息窗口锚坐标系仅在标记旋转时受角度影响。请参阅stackoverflow.com/a/32947599/2711811 - 以获得解释。由于您没有提及任何有关轮换的内容,因此很难知道您要完成什么。如果该链接没有帮助,我建议发布一个包含相关信息的新问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-12-24
  • 1970-01-01
  • 1970-01-01
  • 2018-10-29
  • 2015-03-23
  • 1970-01-01
  • 2017-07-19
相关资源
最近更新 更多