Код полностью реализован в 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.