简体   繁体   English

android地图自动旋转

[英]android maps auto-rotate

If you open the Google maps app, there is a button on the top right of the screen that you can press to center the map on your current location.如果您打开 Google 地图应用程序,屏幕右上角有一个按钮,您可以按下该按钮以将地图置于当前位置的中心。 The button's icon then changes.然后按钮的图标会发生变化。 If you press the same button again, the map auto-rotates based on your compass heading.如果您再次按下同一个按钮,地图会根据您的罗盘航向自动旋转。 In other words, the map becomes egocentric (as opposed to allocentric AKA north always up).换句话说,地图变得以自我为中心(与以异体为中心的又名北总是向上相反)。

Google recently launched maps API V2 for Android and I certainly like it more than the old one. Google 最近推出了适用于 Android 的地图 API V2,我当然比旧版本更喜欢它。 By default, android maps V2 will include the "center on location" button.默认情况下,android maps V2 将包含“位置中心”按钮。 However, pressing it more than once does not enable auto-rotation;但是,多次按下它不会启用自动旋转; it merely tries to center the map on your location again.它只是尝试再次将地图以您的位置为中心。

Does anyone know how I can auto-rotate the map using maps API v2 just like the google maps app does?有谁知道我如何像谷歌地图应用程序一样使用地图 API v2 自动旋转地图? Will I have to implement this functionality myself or is it in the API and i'm just not seeing it?我必须自己实现这个功能还是在 API 中实现,我只是没有看到它? I appreciate all help.我感谢所有帮助。

Ok here's how I think it should be done a year later.好的,这是我认为应该在一年后完成的方式。 Please correct me if you spot any issues.如果您发现任何问题,请纠正我。

Most of the following code deals with a discrepancy between coordinate systems.以下大部分代码处理坐标系之间的差异。 I'm using a rotation vector sensor.我正在使用旋转矢量传感器。 From the docs: Y is tangential to the ground at the device's current location and points towards magnetic north.来自文档: Y is tangential to the ground at the device's current location and points towards magnetic north. Bearing in google maps, on the other hand, seems to point to true north.另一方面,谷歌地图中的方位似乎指向真北。 this page shows how the conversion is done 此页面显示转换是如何完成的

1) get the current declination from your current GPS location 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) calculate bearing from declination and magnetic north 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) update maps 3)更新地图

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

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

I have successfully implemented aleph_null solution and here I will add some details that are not mentioned in the accepted solution:我已经成功实现了 aleph_null 解决方案,在这里我将添加一些在已接受的解决方案中没有提到的细节:

For the above solution to work you need to implement android.hardware.SensorEventListener interface.要使上述解决方案起作用,您需要实现 android.hardware.SensorEventListener 接口。

You need also to register to the SensorEventListener in your onResume and onPause methods as follow:您还需要在 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);
}

Note to "@Bytecode": To avoid flickering, use low value for the sampling period, something like SensorManager.SENSOR_STATUS_ACCURACY_LOW. “@Bytecode”注意事项:为避免闪烁,采样周期使用低值,例如 SensorManager.SENSOR_STATUS_ACCURACY_LOW。

I have noticed also that the sensor sends sometime more data than the device can handle and as a result, the map camera starts to move in a strange way!我还注意到,有时传感器发送的数据比设备可以处理的要多,因此,地图相机开始以一种奇怪的方式移动!

To control the amount of data handled by onSensorChanged, I suggest the following implementation:为了控制 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]);
    }
}

It is possible by registering your application with Sensor Listener for Orientation and getting the angle relative to true north inside onSensorChanged and update camera accordingly.可以通过使用 Sensor Listener for Orientation 注册您的应用程序并获取相对于 onSensorChanged 内的真北的角度并相应地更新相机。 Angle can be used for bearing.角度可用于轴承。 The following code can be used:可以使用以下代码:

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));

}

Sorry, you'll have to implement it yourself with the sensor manager and the camera抱歉,您必须自己使用传感器管理器相机来实现

if those functions were available to the map api V2 they would certainly be either on the GoogleMap or the UiSettings如果这些函数可用于 map api V2,它们肯定会在GoogleMapUiSettings 上

The new Location class already gives you the bearing automatically, why not use it?新的Location类已经自动为您提供了方位,为什么不使用它呢?

Sample code:示例代码:

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));
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM