如何在谷歌地图中更新相机和标记以及折线?

时间:2017-06-06 07:26:06

标签: android google-maps marker polyline

我正在尝试像ola这样的地图应用程序。我画了一条折线,但是当标记移动时我无法更新相机。此外,我没有得到适当的解决方案动画标记与折线。建议我妥善解决我的问题。

以下是代码:

公共类MainActivity扩展AppCompatActivity实现OnMapReadyCallback,View.OnClickListener {

private Context context;
GoogleMap googleMap;
Button btn_start;
Marker marker;
Polyline line;
List<LatLng> list;
LatLng startLatLng = new LatLng(43.182821, -99.292304);
LatLng endLatLng = new LatLng(44.959263, -97.580412);

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    context = MainActivity.this;

    btn_start = (Button) findViewById(R.id.btn_start);
    String urlTopass = makeURL(startLatLng.latitude,
            startLatLng.longitude, endLatLng.latitude,
            endLatLng.longitude);
    new connectAsyncTask(urlTopass).execute();
    btn_start.setOnClickListener(this);

    SupportMapFragment mapFragment =
            (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
    mapFragment.getMapAsync(this);
}

@Override
public void onMapReady(GoogleMap mMap) {
    googleMap = mMap;
    CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(startLatLng, 9);
    googleMap.animateCamera(cameraUpdate);
}

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.btn_start:
            setAnimation(googleMap, list, ResourceUtils.getBitmap(context, R.drawable.ic_car_yellow_btg));
            break;

        default:
            break;
    }
}

private class connectAsyncTask extends AsyncTask<Void, Void, String> {
    private ProgressDialog progressDialog;
    String url;

    connectAsyncTask(String urlPass) {
        url = urlPass;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        progressDialog = new ProgressDialog(context);
        progressDialog.setMessage("Fetching route, Please wait...");
        progressDialog.setIndeterminate(true);
        progressDialog.show();
    }

    @Override
    protected String doInBackground(Void... params) {
        JSONParser jParser = new JSONParser();
        return jParser.getJSONFromUrl(url);
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        progressDialog.hide();
        if (result != null) {
            drawPath(result);
        }
    }
}

public String makeURL(double sourcelat, double sourcelog, double destlat,
                      double destlog) {
    StringBuilder urlString = new StringBuilder();
    urlString.append("http://maps.googleapis.com/maps/api/directions/json");
    urlString.append("?origin=");// from
    urlString.append(Double.toString(sourcelat));
    urlString.append(",");
    urlString.append(Double.toString(sourcelog));
    urlString.append("&destination=");// to
    urlString.append(Double.toString(destlat));
    urlString.append(",");
    urlString.append(Double.toString(destlog));
    urlString.append("&sensor=true&mode=driving&alternatives=true");
    Log.e("url ", " " + urlString);
    return urlString.toString();
}

public class JSONParser {

    InputStream is = null;
    JSONObject jObj = null;
    String json = "";

    public JSONParser() {
    }

    public String getJSONFromUrl(String url) {
        try {
            DefaultHttpClient httpClient = new DefaultHttpClient();
            HttpPost httpPost = new HttpPost(url);

            HttpResponse httpResponse = httpClient.execute(httpPost);
            HttpEntity httpEntity = httpResponse.getEntity();
            is = httpEntity.getContent();

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            BufferedReader reader = new BufferedReader(
                    new InputStreamReader(is, "iso-8859-1"), 8);
            StringBuilder sb = new StringBuilder();
            String line = null;
            while ((line = reader.readLine()) != null) {
                sb.append(line).append("\n");
            }

            json = sb.toString();
            is.close();
        } catch (Exception e) {
            Log.e("Buffer Error", "Error converting result " + e.toString());
        }
        return json;

    }
}

public void drawPath(String result) {
    if (line != null) {
        googleMap.clear();
    }

    googleMap.addMarker(new MarkerOptions().position(startLatLng).icon(
            BitmapDescriptorFactory.fromBitmap(ResourceUtils.getBitmap(context, R.drawable.ic_car_yellow_btg))));
    /*googleMap.addMarker(new MarkerOptions().position(startLatLng).icon(
            BitmapDescriptorFactory.fromResource(R.drawable.car_red)));*/
    try {
        final JSONObject json = new JSONObject(result);
        JSONArray routeArray = json.getJSONArray("routes");
        JSONObject routes = routeArray.getJSONObject(0);
        JSONObject overviewPolylines = routes
                .getJSONObject("overview_polyline");
        String encodedString = overviewPolylines.getString("points");

        list = decodePoly(encodedString);
        for (int z = 0; z < list.size() - 1; z++) {
            LatLng src = list.get(z);
            LatLng dest = list.get(z + 1);
            line = googleMap.addPolyline(new PolylineOptions()
                    .add(new LatLng(src.latitude, src.longitude),
                            new LatLng(dest.latitude, dest.longitude))
                    .width(10).color(Color.BLUE).geodesic(true));
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

private List<LatLng> decodePoly(String encoded) {

    List<LatLng> poly = new ArrayList<>();
    int index = 0, len = encoded.length();
    int lat = 0, lng = 0;

    while (index < len) {
        int b, shift = 0, result = 0;
        do {
            b = encoded.charAt(index++) - 63;
            result |= (b & 0x1f) << shift;
            shift += 5;
        } while (b >= 0x20);
        int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
        lat += dlat;

        shift = 0;
        result = 0;
        do {
            b = encoded.charAt(index++) - 63;
            result |= (b & 0x1f) << shift;
            shift += 5;
        } while (b >= 0x20);
        int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
        lng += dlng;

        LatLng p = new LatLng((((double) lat / 1E5)), (((double) lng / 1E5)));
        poly.add(p);
        Log.e("coords", "LatLng " + p);
    }
    return poly;
}

public static void setAnimation(GoogleMap myMap, final List<LatLng> directionPoint, final Bitmap bitmap) {
    Marker marker = myMap.addMarker(new MarkerOptions()
            .icon(BitmapDescriptorFactory.fromBitmap(bitmap))
            .position(directionPoint.get(0))
            .flat(true));
    /*PolylineOptions rectLine = new PolylineOptions().width(3).color(Color.RED);
    for (int i = 0; i < directionPoint.size(); i++) {
        rectLine.add(directionPoint.get(i));
    }
    myMap.moveCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), 50));*/
    animateMarker(myMap, marker, directionPoint, false);
}

private static void animateMarker(GoogleMap myMap, final Marker marker, final List<LatLng> directionPoint,
                                  final boolean hideMarker) {
    final Handler handler = new Handler();
    final long start = SystemClock.uptimeMillis();
    Projection proj = myMap.getProjection();
    final long duration = 60000;

    final Interpolator interpolator = new LinearInterpolator();

    handler.post(new Runnable() {
        int i = 0;

        @Override
        public void run() {
            long elapsed = SystemClock.uptimeMillis() - start;
            float t = interpolator.getInterpolation((float) elapsed
                    / duration);
            if (i < directionPoint.size())
                marker.setPosition(directionPoint.get(i));
            i++;

            if (t < 1.0) {
                handler.postDelayed(this, 24);
            } else {
                if (hideMarker) {
                    marker.setVisible(false);
                } else {
                    marker.setVisible(true);
                }
            }
        }
    });
}

}

1 个答案:

答案 0 :(得分:1)

首先你需要这个课程:

public interface LatLngInterpolator {
LatLng interpolate(float fraction, LatLng a, LatLng b);

class Linear implements LatLngInterpolator {
    @Override
    public LatLng interpolate(float fraction, LatLng a, LatLng b) {
        double lat = (b.latitude - a.latitude) * fraction + a.latitude;
        double lng = (b.longitude - a.longitude) * fraction + a.longitude;
        return new LatLng(lat, lng);
    }
}

class LinearFixed implements LatLngInterpolator {
    @Override
    public LatLng interpolate(float fraction, LatLng a, LatLng b) {
        double lat = (b.latitude - a.latitude) * fraction + a.latitude;
        double lngDelta = b.longitude - a.longitude;

        // Take the shortest path across the 180th meridian.
        if (Math.abs(lngDelta) > 180) {
            lngDelta -= Math.signum(lngDelta) * 360;
        }
        double lng = lngDelta * fraction + a.longitude;
        return new LatLng(lat, lng);
    }
}

class Spherical implements LatLngInterpolator {

    /* From github.com/googlemaps/android-maps-utils */
    @Override
    public LatLng interpolate(float fraction, LatLng from, LatLng to) {
        // http://en.wikipedia.org/wiki/Slerp
        double fromLat = toRadians(from.latitude);
        double fromLng = toRadians(from.longitude);
        double toLat = toRadians(to.latitude);
        double toLng = toRadians(to.longitude);
        double cosFromLat = cos(fromLat);
        double cosToLat = cos(toLat);

        // Computes Spherical interpolation coefficients.
        double angle = computeAngleBetween(fromLat, fromLng, toLat, toLng);
        double sinAngle = sin(angle);
        if (sinAngle < 1E-6) {
            return from;
        }
        double a = sin((1 - fraction) * angle) / sinAngle;
        double b = sin(fraction * angle) / sinAngle;

        // Converts from polar to vector and interpolate.
        double x = a * cosFromLat * cos(fromLng) + b * cosToLat * cos(toLng);
        double y = a * cosFromLat * sin(fromLng) + b * cosToLat * sin(toLng);
        double z = a * sin(fromLat) + b * sin(toLat);

        // Converts interpolated vector back to polar.
        double lat = atan2(z, sqrt(x * x + y * y));
        double lng = atan2(y, x);
        return new LatLng(toDegrees(lat), toDegrees(lng));
    }

    private double computeAngleBetween(double fromLat, double fromLng, double toLat, double toLng) {
        // Haversine's formula
        double dLat = fromLat - toLat;
        double dLng = fromLng - toLng;
        return 2 * asin(sqrt(pow(sin(dLat / 2), 2) +
                cos(fromLat) * cos(toLat) * pow(sin(dLng / 2), 2)));
    }
}
}

然后您可以使用此类为标记设置动画:

public class MarkerAnimation {

private static final String TAG = MarkerAnimation.class.getSimpleName();
public static ArrayList<GetDirectionsAsync> getDirectionsAsyncs = new ArrayList<>();
static boolean isAnimationRunning = false;

public static void animateMarkerToGB(final Marker marker, final LatLng finalPosition, final LatLngInterpolator latLngInterpolator) {
    final LatLng startPosition = marker.getPosition();
    final Handler handler = new Handler();
    final long start = SystemClock.uptimeMillis();
    final Interpolator interpolator = new AccelerateDecelerateInterpolator();
    final float durationInMs = 3000;


    handler.post(new Runnable() {
        long elapsed;
        float t;
        float v;

        @Override
        public void run() {
            // Calculate progress using interpolator
            elapsed = SystemClock.uptimeMillis() - start;
            t = elapsed / durationInMs;
            v = interpolator.getInterpolation(t);

            marker.setPosition(latLngInterpolator.interpolate(v, startPosition, finalPosition));

            // Repeat till progress is complete.
            if (t < 1) {
                // Post again 16ms later.
                handler.postDelayed(this, 16);
            }
        }
    });
}

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static void animateMarkerToHC(final Marker marker, final LatLng finalPosition, final LatLngInterpolator latLngInterpolator) {
    final LatLng startPosition = marker.getPosition();

    ValueAnimator valueAnimator = new ValueAnimator();
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            float v = animation.getAnimatedFraction();
            LatLng newPosition = latLngInterpolator.interpolate(v, startPosition, finalPosition);
            marker.setPosition(newPosition);
        }
    });
    valueAnimator.setFloatValues(0, 1); // Ignored.
    valueAnimator.setDuration(3000);
    valueAnimator.start();
}

@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public static void animateMarkerToICS(Marker marker, LatLng finalPosition, final LatLngInterpolator latLngInterpolator) {

//        List<LatLng> list = new ArrayList<>();
//        list.add(finalPosition);
//        animateMarkerToICSRecursive(marker, list, latLngInterpolator, true);

    try {
        animateMarkerToICSRecursive(marker, finalPosition, latLngInterpolator, true);            
//if(MapUtils.distance(marker.getPosition(), finalPosition) 
//< 100
//                    || MapUtils.distance(marker.getPosition(), 
//finalPosition) > 500){
//                List<LatLng> list = new ArrayList<>();
//                animateMarkerToICSRecursive(marker, finalPosition, 
//latLngInterpolator, true);
//            }
//            else{
//                getDirectionsAsyncs.add(new 
//GetDirectionsAsync(marker, finalPosition, latLngInterpolator));
//                if(getDirectionsAsyncs.size() == 1){
//                    getDirectionsAsyncs.get(0).execute();
//                }
//            }
    } catch (Exception e) {
        e.printStackTrace();
        try {
            marker.setPosition(finalPosition);
        } catch (Exception e1) {
            e1.printStackTrace();
        }
    }

}

private static void checkAndExecute() {
    if (getDirectionsAsyncs.size() > 0) {
        getDirectionsAsyncs.get(0).execute();
    }
}

@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public static void animateMarkerToICSRecursive(final Marker marker, final List<LatLng> list,
                                               final LatLngInterpolator latLngInterpolator, final boolean rotation) {
    if (list.size() > 0) {
        final LatLng finalPosition = list.remove(0);
        TypeEvaluator<LatLng> typeEvaluator = new TypeEvaluator<LatLng>() {
            @Override
            public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) {
                return latLngInterpolator.interpolate(fraction, startValue, endValue);
            }
        };
        Property<Marker, LatLng> property = Property.of(Marker.class, LatLng.class, "position");
        ObjectAnimator animator = ObjectAnimator.ofObject(marker, property, typeEvaluator, finalPosition);
        animator.setDuration((long) (10.0d * MapUtils.distance(marker.getPosition(), finalPosition)));
        animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {
                isAnimationRunning = true;
            }

            @Override
            public void onAnimationEnd(Animator animator) {
                marker.setPosition(finalPosition);
                isAnimationRunning = false;
                if (list.size() > 0) {
                    animateMarkerToICSRecursive(marker, list, latLngInterpolator, rotation);
                }
            }

            @Override
            public void onAnimationCancel(Animator animator) {

            }

            @Override
            public void onAnimationRepeat(Animator animator) {

            }
        });

        if (rotation) {
            //marker.setRotation((float) MapUtils.getBearing(marker.getPosition(), finalPosition));
            MapUtils.rotateMarker(marker, (float) MapUtils.getBearing(marker.getPosition(), finalPosition));
        }
        if (!isAnimationRunning) {
            animator.start();
        }
    }
}

@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public static void animateMarkerToICSRecursive(final Marker marker, final LatLng finalPosition,
                                               final LatLngInterpolator latLngInterpolator, final boolean rotation) {
    TypeEvaluator<LatLng> typeEvaluator = new TypeEvaluator<LatLng>() {
        @Override
        public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) {
            return latLngInterpolator.interpolate(fraction, startValue, endValue);
        }
    };
    Property<Marker, LatLng> property = Property.of(Marker.class, LatLng.class, "position");
    ObjectAnimator animator = ObjectAnimator.ofObject(marker, property, typeEvaluator, finalPosition);
    animator.setDuration((long) (1000));
    animator.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animator) {
            isAnimationRunning = true;
        }

        @Override
        public void onAnimationEnd(Animator animator) {
            marker.setPosition(finalPosition);
            isAnimationRunning = false;

        }

        @Override
        public void onAnimationCancel(Animator animator) {

        }

        @Override
        public void onAnimationRepeat(Animator animator) {

        }
    });

    if (rotation) {
        //marker.setRotation((float) MapUtils.getBearing(marker.getPosition(), finalPosition));
        MapUtils.rotateMarker(marker, (float) MapUtils.getBearing(marker.getPosition(), finalPosition));
    }
    if (!isAnimationRunning) {
        animator.start();
    }
}

static class GetDirectionsAsync extends AsyncTask<String, String, String> {

    LatLng source, destination;
    Marker marker;
    LatLngInterpolator latLngInterpolator;

    public GetDirectionsAsync(Marker marker, LatLng destination, LatLngInterpolator latLngInterpolator) {
        this.source = marker.getPosition();
        this.destination = destination;
        this.marker = marker;
        this.latLngInterpolator = latLngInterpolator;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }

    @Override
    protected String doInBackground(String... strings) {
        try {
            Response response = RestClient.getGoogleApiServices().getDirections(source.latitude + "," + source.longitude,
                    destination.latitude + "," + destination.longitude, false, "driving", false);
            String responseStr = new String(((TypedByteArray) response.getBody()).getBytes());
            return responseStr;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        if (result != null) {
            final List<LatLng> list = MapUtils.getLatLngListFromPath(result);
            animateMarkerToICSRecursive(marker, list, latLngInterpolator, true);
        }
        getDirectionsAsyncs.remove(0);
        checkAndExecute();

    }
}


}

您需要传递上述类中路径的所有LatLng列表,如下所示:

 MarkerAnimation.animateMarkerToICS(driverLocationMarker, destinationLatLng, new LatLngInterpolator.Spherical());

希望这有帮助

编辑:

这是标记旋转的代码: d         public static void rotateMarker(final marker marker,final float toRotation){         final Handler handler = new Handler();         final long start = SystemClock.uptimeMillis();         final float startRotation = marker.getRotation();         最后的持续时间= 700;

    final Interpolator interpolator = new LinearInterpolator();

    handler.post(new Runnable() {
        @Override
        public void run() {
            long elapsed = SystemClock.uptimeMillis() - start;
            float t = interpolator.getInterpolation((float) elapsed / duration);

            float rot = t * toRotation + (1 - t) * startRotation;

            marker.setRotation(-rot > 180 ? rot / 2 : rot);
            if (t < 1.0) {
                // Post again 16ms later.
                handler.postDelayed(this, 16);
            }
        }
    });
}