web-dev-qa-db-fra.com

android maps rotation automatique

Si vous ouvrez l'application Google maps, il y a un bouton en haut à droite de l'écran sur lequel vous pouvez appuyer pour centrer la carte sur votre position actuelle. L'icône du bouton change alors. Si vous appuyez à nouveau sur le même bouton, la carte pivote automatiquement en fonction du cap de votre boussole. En d'autres termes, la carte devient égocentrique (par opposition à AKA allocentrique toujours vers le haut).

Google a récemment lancé l'API de cartes V2 pour Android et je l'aime certainement plus que l'ancienne. Par défaut, Android maps V2 inclura le "centre sur l'emplacement") ". Toutefois, si vous appuyez dessus plusieurs fois, la rotation automatique n'est pas activée; elle tente simplement de recentrer la carte sur votre position.

Est-ce que quelqu'un sait comment faire pivoter automatiquement la carte à l'aide de l'API Maps v2, tout comme l'application Google Maps? Dois-je implémenter cette fonctionnalité moi-même ou est-ce dans l'API et je ne le vois tout simplement pas? J'apprécie toute aide.

21
aleph_null

Ok, voici comment je pense que cela devrait être fait un an plus tard. Veuillez me corriger si vous repérez des problèmes.

La plupart du code suivant traite d'une divergence entre les systèmes de coordonnées. J'utilise un capteur vectoriel de rotation. De la documentation: Y is tangential to the ground at the device's current location and points towards magnetic north. Le relèvement dans google maps, en revanche, semble pointer vers le nord vrai. cette page montre comment la conversion est effectuée

1) Obtenez la déclinaison actuelle de votre position GPS actuelle

@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) calculer le relèvement à partir de la déclinaison et du nord magnétique

    @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) Mettre à jour les cartes

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

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

J'ai réussi à implémenter la solution aleph_null et ici j'ajouterai quelques détails qui ne sont pas mentionnés dans la solution acceptée:

Pour que la solution ci-dessus fonctionne, vous devez implémenter l'interface Android.hardware.SensorEventListener.

Vous devez également vous inscrire à SensorEventListener dans vos méthodes onResume et onPause comme suit:

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

Remarque concernant "@Bytecode": pour éviter le scintillement, utilisez une valeur faible pour la période d'échantillonnage, quelque chose comme SensorManager.SENSOR_STATUS_ACCURACY_LOW.

J'ai également remarqué que le capteur envoie parfois plus de données que ce que l'appareil peut gérer et, par conséquent, la caméra cartographique commence à bouger d'une manière étrange!

Pour contrôler la quantité de données gérées par onSensorChanged, je suggère l'implémentation suivante:

@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]);
    }
}
7
Techi50

Il est possible d'enregistrer votre application auprès de Sensor Listener for Orientation et d'obtenir l'angle par rapport au nord vrai à l'intérieur de onSensorChanged et de mettre à jour la caméra en conséquence. L'angle peut être utilisé pour le roulement. Le code suivant peut être utilisé:

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

}
2
Prashant

Désolé, vous devrez l'implémenter vous-même avec le gestionnaire de capteurs et le caméra

si ces fonctions étaient disponibles pour la carte api V2, elles seraient certainement soit sur le GoogleMap soit sur le iSettings

0
Budius