安卓地图自动旋转

22
如果您打开Google地图应用程序,在屏幕右上方有一个按钮,您可以按下该按钮将地图居中在您当前的位置。按钮的图标随即更改。如果您再次按同一按钮,则地图会根据指南针方向自动旋转。换句话说,地图变得以自我为中心(与以北为上的分配中心相对)。
Google最近推出了Android地图API V2,我肯定比旧版本更喜欢它。默认情况下,android maps V2将包括“定位到位置”按钮。然而,多次按下此按钮并不会启用自动旋转功能;它仅仅是尝试再次将地图居中在您的位置。
请问有人知道如何像Google地图应用程序那样使用maps API v2自动旋转地图吗?我是否需要自己实现此功能,还是API中已经有此功能但我没有看到?非常感谢您的帮助。

那很有帮助...我甚至不知道那个功能,谢谢。对我来说,它在v7上运行良好。 - Martin Hansen
嗨,我想做同样的事情,请分享你的解决方案,如果你已经完成了这个任务。 - AITAALI_ABDERRAHMANE
5个回答

27

好的,这是我认为应该在一年后完成的方式。如果您发现任何问题,请纠正我。

以下大部分代码都涉及坐标系统之间的差异。我正在使用旋转向量传感器。来自文档:Y 在设备当前位置切向地面,并指向磁北极。另一方面,Google 地图中的方位似乎指向真北。此页面显示如何进行转换

1)从当前 GPS 位置获取当前偏角

@Override
public void onLocationChanged(Location location) {
    GeomagneticField field = new GeomagneticField(
            (float)location.getLatitude(),
            (float)location.getLongitude(),
            (float)location.getAltitude(),
            System.currentTimeMillis()
        );

    // getDeclination returns degrees
    mDeclination = field.getDeclination();
} 

2) 从偏角和磁北方计算方位角

    @Override
public void onSensorChanged(SensorEvent event) {
    if(event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
        SensorManager.getRotationMatrixFromVector(
                mRotationMatrix , event.values);
        float[] orientation = new float[3];
        SensorManager.getOrientation(mRotationMatrix, orientation);
        float bearing = Math.toDegrees(orientation[0]) + mDeclination;
        updateCamera(bearing);  
    }
}

3) 更新地图

private void updateCamera(float bearing) {
    CameraPosition oldPos = mMap.getCameraPosition();

    CameraPosition pos = CameraPosition.builder(oldPos).bearing(bearing).build();
            mMap.moveCamera(CameraUpdateFactory.newCameraPosition(pos));
}

2
private float[] mRotationMatrix = new float[16]; getRotationMatrixFromVector 将根据事件中的值填充 mRotationMatrix - aleph_null
这会在地图上创建闪烁效果,我该如何限制旋转? - Bytecode
需要注意的是,getRotationMatrixFromVector() 仅适用于 API 9+。对于支持旧应用程序的人来说,这应该是相关的。 - AlexVPerl
2
嗨,我实现了上面的代码,我的应用程序中有旋转功能,但谷歌地图不断向上移动。 - Azfaar kabir Siddiqui
和mDeclination呢? - Tushar Monirul
您可以在此帖子的第一个代码中看到以下内容:“mDeclination = field.getDeclination();”。field是GeomagneticField的实例。如果您搜索方法“getDeclination()”,您会发现它返回浮点数;因此,mDeclination是浮点数。您还可以在第二个代码中看到以下内容:“float bearing = Math.toDegrees(orientation[0]) + mDeclination;”,因此可以得出这是一个浮点数。 - Wilhelm Sorban

8

我已经成功实现了aleph_null的解决方案,这里我将添加一些未在接受的解决方案中提到的细节:

为了使上述解决方案能够工作,您需要实现android.hardware.SensorEventListener接口。

您还需要在onResume和onPause方法中注册SensorEventListener,如下所示:

@Override
    protected void onResume() {
     super.onResume();
     mSensorManager.registerListener(this,
             mRotVectSensor,
             SensorManager.SENSOR_STATUS_ACCURACY_LOW);
    }

@Override
protected void onPause() {
    // unregister listener
    super.onPause();
    mSensorManager.unregisterListener(this);
}

给"@Bytecode"的提示:为了避免闪烁,使用较低的采样周期,例如SensorManager.SENSOR_STATUS_ACCURACY_LOW。

我还注意到传感器有时会发送比设备处理能力更多的数据,结果地图相机开始以奇怪的方式移动!

为了控制onSensorChanged处理的数据量,我建议采用以下实现:

@Override
public void onSensorChanged(SensorEvent event) {
    if(event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
        SensorManager.getRotationMatrixFromVector(
                mRotationMatrix, event.values);
        float[] orientation = new float[3];
        SensorManager.getOrientation(mRotationMatrix, orientation);
        if (Math.abs(Math.toDegrees(orientation[0]) - angle) > 0.8) {
            float bearing = (float) Math.toDegrees(orientation[0]) + mDeclination;
            updateCamera(bearing);
        }
        angle = Math.toDegrees(orientation[0]);
    }
}

1
mRotVectSensor - theapache64
角度在哪里定义? - suulisin
mRotVectSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);mRotVectSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR); - Itapox

2

通过向Sensor Listener注册您的应用程序并在onSensorChanged中获取相对于真北的角度,可以实现相应更新相机。该角度可用于方位角。以下代码可供使用:

Instead of using Sensor.TYPE_ORIENTATION try using getOrinetation api. Sensor.TYPE_ORIENTATION
has been deprecated.

@Override
protected void onResume() {
    // TODO Auto-generated method stub
    super.onResume();
    if (sensorManager != null)
        sensorManager.registerListener(this,
                sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
                SensorManager.SENSOR_DELAY_GAME);
}

public void onSensorChanged(SensorEvent event) {

    float degree = Math.round(event.values[0]);

    Log.d(TAG, "Degree ---------- " + degree);

    updateCamera(degree);

}

private void updateCamera(float bearing) {
    CameraPosition oldPos = googleMap.getCameraPosition();

    CameraPosition pos = CameraPosition.builder(oldPos).bearing(bearing)
            .build();

    googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(pos));

}

0

0
新的位置类已经自动提供了方位角,为什么不使用它呢?
示例代码:
private void updateCameraBearing(GoogleMap googleMap, Location myLoc) {
    if ( googleMap == null) return;
    CameraPosition camPos = CameraPosition
            .builder(googleMap.getCameraPosition())
            .bearing(myLoc.getBearing())
             // if you want to stay centered - then add the line below
            .target(new LatLng(myLoc.getLatitude(), myLoc.getLongitude()))
            .build();
    googleMap.animateCamera(CameraUpdateFactory.newCameraPosition(camPos));
}

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