Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
747 views
in Technique[技术] by (71.8m points)

android - Animate camera to position and set panning in google maps

I'm trying to achieve similar to how navigation in google maps works, check the below image for reference. In google maps, the marker looks to be at a static location except the camera is changing


.

enter image description here

To achieve this I animate the marker every time my location changes and later I position it towards the bottom of the screen by panning it by -300px in Y coordinate.

But I cannot animate the camera for change in location an moving the screen 300px down at the same time.

When I animate the camera for change in location the marker moves exactly to the centre of the screen and later when I move the camera 300px below other animation takes place which looks very annoying.

Is there a way I can achieve what google maps do? Any reference or help is appreciated.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The code is completely implemented in the onLocationChanged but as documented some of it can be extracted during init.

Essentially what is being done is a shadow target is computed from the current location using the distance derived from a screen pixel offset, extrapolated using a computed bearing from last location.

In the screen recording (below), the green circle represents the current location (also depicted by the map location dot) and the blue circle represents the shadow target which is always in the center of the screen as a result of being the target of the map animate.

Here's a quick drawing of concept:

enter image description here

And the code (with a screen recording below):

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

Notes:

  • When the zoom changes, the offsetDistance needs to be recomputed. (But as noted it does not need to be done every location changed.)
  • Bearing is shown in concept diagram as 0-360 but is actually -180-180.
  • As you can see, most of the work is done in the SphericalUtil class.

enter image description here


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...