Android maps V2中的newLatLngBounds方法如何设置方向?

26

我正在使用这个布局与新的Android Maps V2:

<fragment xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:map="http://schemas.android.com/apk/res-auto"
  android:id="@+id/map"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  class="com.google.android.gms.maps.SupportMapFragment"
  map:cameraBearing="270"/>

我正在尝试使用newLatLngBounds(LatLngBounds bounds, int padding)方法来缩放和查看地图中的所有标记,但相机方向被设为了0。

谷歌开发者文档上的描述如下:

public static CameraUpdate newLatLngBounds (LatLngBounds bounds, int padding) (...)。返回的CameraUpdate具有0度方向和0度倾斜度。(...)

我该如何更改方向值?

我尝试在调用newLatLngBounds后编程设置新的方向,类似于以下内容:

mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 100));
mMap.moveCamera(CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder()
.target(mMap.getCameraPosition().target)
.zoom(mMap.getCameraPosition().zoom)
.bearing(270)
.build()));

但是当我这样做时,有些标记不会显示。


@Mike-Bell,没有,我认为目前的安卓地图库不可能实现这个功能。 - pedroca
这种方法需要地图视图可见,否则相机的位置将默认在伦敦某处。 - Petru Lutenco
3个回答

17

我有一个替代方案,我曾经遇到过相同的问题。我将展示如何将边界转换为缩放级别,然后我们只需使用CameraPosition.builder()创建正确的位置。

private static final double LN2 = 0.6931471805599453;
    private static final int WORLD_PX_HEIGHT = 256;
    private static final int WORLD_PX_WIDTH = 256;
    private static final int ZOOM_MAX = 21;

    public int getBoundsZoomLevel(LatLngBounds bounds, int mapWidthPx, int mapHeightPx){

        LatLng ne = bounds.northeast;
        LatLng sw = bounds.southwest;

        double latFraction = (latRad(ne.latitude) - latRad(sw.latitude)) / Math.PI;

        double lngDiff = ne.longitude - sw.longitude;
        double lngFraction = ((lngDiff < 0) ? (lngDiff + 360) : lngDiff) / 360;

        double latZoom = zoom(mapHeightPx, WORLD_PX_HEIGHT, latFraction);
        double lngZoom = zoom(mapWidthPx, WORLD_PX_WIDTH, lngFraction);

        int result = Math.min((int)latZoom, (int)lngZoom);
        return Math.min(result, ZOOM_MAX);
    }

    private double latRad(double lat) {
        double sin = Math.sin(lat * Math.PI / 180);
        double radX2 = Math.log((1 + sin) / (1 - sin)) / 2;
        return Math.max(Math.min(radX2, Math.PI), -Math.PI) / 2;
    }
    private double zoom(int mapPx, int worldPx, double fraction) {
        return Math.floor(Math.log(mapPx / worldPx / fraction) / LN2);
    }

然后您可以使用此代码,并在边界框中添加方向和/或倾斜:

            LatLngBounds bounds = LatLngBounds.builder()
                    .include(swCorner)
                    .include(neCorner).build();
            CameraPosition cp = new CameraPosition.Builder()
                    .bearing(randomBearing())
                    .tilt(randomTilt())
                    .target(latLng)
                    .zoom(getBoundsZoomLevel(bounds, findViewById(R.id.map).getMeasuredWidth(), findViewById(R.id.map).getMeasuredHeight()))
                    .build();
            CameraUpdate cu = CameraUpdateFactory.newCameraPosition(cp);
            mMap.animateCamera(cu);

这将起作用(您需要更改mMap为实际地图变量并将id更改为您的地图id)。

祝好运!我从这篇帖子中获取了boundZoomLevel:如何在使用map.fitBounds之前确定LatLngBounds的缩放级别?如果您有时间,请点赞该答案!


2
太好了,谢谢!但我有两个疑问。我认为WORLD_PX常量实际上是256 dp,而视图尺寸以px返回,这可能导致错误的缩放。此外,在旋转后,边界的“角落”可能会旋转到地图之外。理想情况下,坐标旋转应在确定边界之前发生。(我不确定是否需要或有益于Math.floor。) - Peter McLennan
4
彼得说得对,需要根据密度来纠正WORLD PX => (int) (GLOBE_WIDTH * context.getResources().getDisplayMetrics().density) - Jordy
@Jordy,能否请你澄清一下,我写这个已经有很长时间了,不太记得当时在做什么。应该替换哪个PX?宽度和高度都用这个变量替换吗? - Jono
1
我已经添加了一个 Gist,其中包含当前有效的 Kotlin 代码片段。https://gist.github.com/kibotu/f9bda6831573e8226fc3298df8ac73be - Jan Rabe

5
可以的!只需要使用以下代码:https://developers.google.com/android/reference/com/google/android/gms/maps/GoogleMap#animateCamera(com.google.android.gms.maps.CameraUpdate,int,com.google.android.gms.maps.GoogleMap.CancelableCallback),并实现一个CancelableCallback,在onFinish()方法中添加以下代码:https://developers.google.com/android/reference/com/google/android/gms/maps/GoogleMap.CancelableCallback#onFinish()。这段代码可以改变方向。当然,你不会得到单个动画,但是它会起作用!
mMap.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 100)/*,DURATION_IN_MS_IF_NEEDED*/,new GoogleMap.CancelableCallback(){
    @Override
    public void onCancel() {
        //DO SOMETHING HERE IF YOU WANT TO REACT TO A USER TOUCH WHILE ANIMATING
    }
    @Override
    public void onFinish() {
        mMap.animateCamera(CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder()
/*.target(mMap.getCameraPosition().target)
.zoom(mMap.getCameraPosition().zoom)*/
.bearing(270)
.build()));
    }
});

我认为您不需要目标和缩放,因为它们应该由先前的动画管理,所以我将它们保留为注释状态

编辑 仔细查看API后,我有一个可能可行的方法(现在无法测试,请查看: 拥有LatLngBounds,您可以获得最适合该区域的缩放级别(它取决于设备尺寸,因此您必须在运行时获取视图尺寸),然后,当您拥有缩放级别(您也有LatLngBounds的中心点),您可以使用一个唯一的动画进行相机更新: https://developers.google.com/android/reference/com/google/android/gms/maps/model/CameraPosition,构造函数允许设置值,或者您可以像以前一样使用生成器。

您可以在线找到各种方法来做到这一点,例如(只是快速搜索在线获得javascript版本 https://dev59.com/8W025IYBdhLWcg3wW0yx#13274361

希望这能帮助您解决问题!


2
这个问题的整个意义在于创建一个单一的地图动画,可以同时完成两件事情。 - Nima GT
它做两件事情连接在一起。没有其他同时完成的方法! - N Dorigatti
另外,我需要查看所有标记,这就是为什么我使用newLatLngBound()的原因。如果我改变方位而不缩放,则在该动画之后某些标记将被隐藏。 - pedroca
@pedroca,如果您取消注释目标和缩放,代码是否有效? - N Dorigatti
2
应用程序在将目标设为null后崩溃。 - Rishabh Saxena
显示剩余4条评论

-4

在Google的CameraUpdateFactory上出现了问题,但我花了一些时间解决了它,只需要微小的时间跨度!

public void zoomToBounds() {
    LatLngBounds latLngBounds = getBoundsOfInput(inputPoints);
    final int PADDING = 20;

    final CameraPosition now = map.getCameraPosition();
    final float tilt = map.getCameraPosition().tilt;
    final float bearing = map.getCameraPosition().bearing;
    final LatLng[] target = new LatLng[1];
    final float[] zoom = new float[1];

    map.animateCamera(CameraUpdateFactory.newLatLngBounds(latLngBounds, PADDING), 1, null);

    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            target[0] = map.getCameraPosition().target;
            zoom[0] = map.getCameraPosition().zoom;
        }
    }, 10);
    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            map.animateCamera(CameraUpdateFactory.newCameraPosition(now), 1, null);
        }
    }, 30);

    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            map.animateCamera(CameraUpdateFactory.newCameraPosition(new CameraPosition(target[0], zoom[0], tilt, bearing)));
        }
    }, 60);
}

看起来很乱,但是能用

3个处理程序完成任务,每个postdelay必须大于前一个


使用时间间隔并不是一个好主意,旋转和外部事件可能会导致不可预测的行为。 - N Dorigatti

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接