Android地图:如何在地图上设置折线动画?

时间:2017-04-08 10:16:11

标签: android google-maps animation maps polyline

当我从A点在地图上绘制折线时 - > B,我要求用动画绘制折线。好像来自A-> B折线继续绘制。

我使用以下链接作为参考:

https://github.com/amalChandran/google-maps-route-animation

使用该解决方案,我能够为折线设置动画,但折线本身并不合适。它没有通过道路。解决方案的原始APK也有同样的错误。

有人可以帮我找一个合适的解决方案

5 个答案:

答案 0 :(得分:3)

您也可以尝试使用此参考 https://github.com/mohak1712/UberUX?utm_source=android-arsenal.com&utm_medium=referral&utm_campaign=6129

ValueAnimator - 用于设置叠加层和折线的动画

ValueAnimator tAnimator = ValueAnimator.ofFloat(0, 1);
       tAnimator.setRepeatCount(ValueAnimator.INFINITE);
       tAnimator.setRepeatMode(ValueAnimator.RESTART);
       tAnimator.setInterpolator(new LinearInterpolator());
       tAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
           @Override
           public void onAnimationUpdate(ValueAnimator valueAnimator) {
              // animate here
           }
       });

PolyLines - 用于在地图上绘制线条

 PolylineOptions greyOptions = new PolylineOptions();
        greyOptions.width(10);
        greyOptions.color(Color.GRAY);
        greyOptions.startCap(new SquareCap());
        greyOptions.endCap(new SquareCap());
        greyOptions.jointType(ROUND);
        greyPolyLine = mMap.addPolyline(greyOptions);

答案 1 :(得分:1)

从Google控制台启用Direction API。将google_api_key_app中的strings.xml替换为

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Color;
import android.os.AsyncTask;
import android.util.Log;
import android.view.animation.LinearInterpolator;

import androidx.appcompat.app.AppCompatActivity;

import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.Polyline;
import com.google.android.gms.maps.model.PolylineOptions;
import com.google.android.gms.maps.model.SquareCap;

import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;

import static com.google.android.gms.maps.model.JointType.ROUND;

public class GetPathFromLocation extends AsyncTask<String, Void, PolylineOptions> {

    private Context context;
    private String TAG = "GetPathFromLocation";
    private LatLng source, destination;
    private ArrayList<LatLng> wayPoint;
    private GoogleMap mMap;
    private boolean animatePath, repeatDrawingPath;
    private DirectionPointListener resultCallback;

    //https://www.mytrendin.com/draw-route-two-locations-google-maps-android/
    //https://www.androidtutorialpoint.com/intermediate/google-maps-draw-path-two-points-using-google-directions-google-map-android-api-v2/

    public GetPathFromLocation(Context context, LatLng source, LatLng destination, ArrayList<LatLng> wayPoint, GoogleMap mMap, boolean animatePath, boolean repeatDrawingPath, DirectionPointListener resultCallback) {
        this.context = context;
        this.source = source;
        this.destination = destination;
        this.wayPoint = wayPoint;
        this.mMap = mMap;
        this.animatePath = animatePath;
        this.repeatDrawingPath = repeatDrawingPath;
        this.resultCallback = resultCallback;
    }

    synchronized public String getUrl(LatLng source, LatLng dest, ArrayList<LatLng> wayPoint) {

        String url = "https://maps.googleapis.com/maps/api/directions/json?sensor=false&mode=driving&origin="
                + source.latitude + "," + source.longitude + "&destination=" + dest.latitude + "," + dest.longitude;
        for (int centerPoint = 0; centerPoint < wayPoint.size(); centerPoint++) {
            if (centerPoint == 0) {
                url = url + "&waypoints=optimize:true|" + wayPoint.get(centerPoint).latitude + "," + wayPoint.get(centerPoint).longitude;
            } else {
                url = url + "|" + wayPoint.get(centerPoint).latitude + "," + wayPoint.get(centerPoint).longitude;
            }
        }
        url = url + "&key=" + context.getString(R.string.google_api_key_app);

        Helper.showLog("Direction_URL: " + url);

        return url;
    }

    public int getRandomColor() {
        Random rnd = new Random();
        return Color.argb(255, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
    }

    @Override
    protected PolylineOptions doInBackground(String... url) {

        String data;

        try {
            InputStream inputStream = null;
            HttpURLConnection connection = null;
            try {
                URL directionUrl = new URL(getUrl(source, destination, wayPoint));
                connection = (HttpURLConnection) directionUrl.openConnection();
                connection.connect();
                inputStream = connection.getInputStream();

                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                StringBuffer stringBuffer = new StringBuffer();

                String line = "";
                while ((line = bufferedReader.readLine()) != null) {
                    stringBuffer.append(line);
                }

                data = stringBuffer.toString();
                bufferedReader.close();

            } catch (Exception e) {
                Log.e(TAG, "Exception : " + e.toString());
                return null;
            } finally {
                inputStream.close();
                connection.disconnect();
            }
            Log.e(TAG, "Background Task data : " + data);

            //Second AsyncTask

            JSONObject jsonObject;
            List<List<HashMap<String, String>>> routes = null;

            try {
                jsonObject = new JSONObject(data);
                // Starts parsing data
                DirectionHelper helper = new DirectionHelper();
                routes = helper.parse(jsonObject);
                Log.e(TAG, "Executing Routes : "/*, routes.toString()*/);

                //Third AsyncTask

                ArrayList<LatLng> points;
                PolylineOptions lineOptions = null;

                // Traversing through all the routes
                for (int i = 0; i < routes.size(); i++) {
                    points = new ArrayList<>();
                    lineOptions = new PolylineOptions();

                    // Fetching i-th route
                    List<HashMap<String, String>> path = routes.get(i);

                    // Fetching all the points in i-th route
                    for (int j = 0; j < path.size(); j++) {
                        HashMap<String, String> point = path.get(j);

                        double lat = Double.parseDouble(point.get("lat"));
                        double lng = Double.parseDouble(point.get("lng"));
                        LatLng position = new LatLng(lat, lng);

                        points.add(position);
                    }

                    // Adding all the points in the route to LineOptions
                    lineOptions.addAll(points);
                    lineOptions.width(8);
                    lineOptions.color(Color.BLACK);
                    //lineOptions.color(getRandomColor());

                    if (animatePath) {
                        final ArrayList<LatLng> finalPoints = points;
                        ((AppCompatActivity) context).runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                PolylineOptions polylineOptions;
                                final Polyline greyPolyLine, blackPolyline;
                                final ValueAnimator polylineAnimator;

                                LatLngBounds.Builder builder = new LatLngBounds.Builder();
                                for (LatLng latLng : finalPoints) {
                                    builder.include(latLng);
                                }
                                polylineOptions = new PolylineOptions();
                                polylineOptions.color(Color.GRAY);
                                polylineOptions.width(8);
                                polylineOptions.startCap(new SquareCap());
                                polylineOptions.endCap(new SquareCap());
                                polylineOptions.jointType(ROUND);
                                polylineOptions.addAll(finalPoints);
                                greyPolyLine = mMap.addPolyline(polylineOptions);

                                polylineOptions = new PolylineOptions();
                                polylineOptions.width(8);
                                polylineOptions.color(Color.BLACK);
                                polylineOptions.startCap(new SquareCap());
                                polylineOptions.endCap(new SquareCap());
                                polylineOptions.zIndex(5f);
                                polylineOptions.jointType(ROUND);

                                blackPolyline = mMap.addPolyline(polylineOptions);
                                polylineAnimator = ValueAnimator.ofInt(0, 100);
                                polylineAnimator.setDuration(2000);
                                polylineAnimator.setInterpolator(new LinearInterpolator());
                                polylineAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                                    @Override
                                    public void onAnimationUpdate(ValueAnimator valueAnimator) {
                                        List<LatLng> points = greyPolyLine.getPoints();
                                        int percentValue = (int) valueAnimator.getAnimatedValue();
                                        int size = points.size();
                                        int newPoints = (int) (size * (percentValue / 100.0f));
                                        List<LatLng> p = points.subList(0, newPoints);
                                        blackPolyline.setPoints(p);
                                    }
                                });

                                polylineAnimator.addListener(new Animator.AnimatorListener() {
                                    @Override
                                    public void onAnimationStart(Animator animation) {

                                    }

                                    @Override
                                    public void onAnimationEnd(Animator animation) {
                                        if (repeatDrawingPath) {
                                            List<LatLng> greyLatLng = greyPolyLine.getPoints();
                                            if (greyLatLng != null) {
                                                greyLatLng.clear();

                                            }
                                            polylineAnimator.start();
                                        }
                                    }

                                    @Override
                                    public void onAnimationCancel(Animator animation) {
                                        polylineAnimator.cancel();
                                    }

                                    @Override
                                    public void onAnimationRepeat(Animator animation) {
                                    }
                                });
                                polylineAnimator.start();
                            }
                        });
                    }

                    Log.e(TAG, "PolylineOptions Decoded");
                }

                // Drawing polyline in the Google Map for the i-th route
                if (lineOptions != null) {
                    return lineOptions;
                } else {
                    return null;
                }

            } catch (Exception e) {
                Log.e(TAG, "Exception in Executing Routes : " + e.toString());
                return null;
            }

        } catch (Exception e) {
            Log.e(TAG, "Background Task Exception : " + e.toString());
            return null;
        }
    }

    @Override
    protected void onPostExecute(PolylineOptions polylineOptions) {
        super.onPostExecute(polylineOptions);
        if (resultCallback != null && polylineOptions != null)
            resultCallback.onPath(polylineOptions);
    }
}

DirectionHelper.java

import com.google.android.gms.maps.model.LatLng;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class DirectionHelper {

    public List<List<HashMap<String, String>>> parse(JSONObject jObject) {

        List<List<HashMap<String, String>>> routes = new ArrayList<>();
        JSONArray jRoutes;
        JSONArray jLegs;
        JSONArray jSteps;

        try {

            jRoutes = jObject.getJSONArray("routes");

            /** Traversing all routes */
            for (int i = 0; i < jRoutes.length(); i++) {
                jLegs = ((JSONObject) jRoutes.get(i)).getJSONArray("legs");
                List path = new ArrayList<>();

                /** Traversing all legs */
                for (int j = 0; j < jLegs.length(); j++) {
                    jSteps = ((JSONObject) jLegs.get(j)).getJSONArray("steps");

                    /** Traversing all steps */
                    for (int k = 0; k < jSteps.length(); k++) {
                        String polyline = "";
                        polyline = (String) ((JSONObject) ((JSONObject) jSteps.get(k)).get("polyline")).get("points");
                        List<LatLng> list = decodePoly(polyline);

                        /** Traversing all points */
                        for (int l = 0; l < list.size(); l++) {
                            HashMap<String, String> hm = new HashMap<>();
                            hm.put("lat", Double.toString((list.get(l)).latitude));
                            hm.put("lng", Double.toString((list.get(l)).longitude));
                            path.add(hm);
                        }
                    }
                    routes.add(path);
                }
            }

        } catch (JSONException e) {
            e.printStackTrace();
        } catch (Exception e) {
        }


        return routes;
    }

    //Method to decode polyline points
    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);
        }

        return poly;
    }
}

DirectionPointListener.java

import com.google.android.gms.maps.model.PolylineOptions;

public interface DirectionPointListener {
    public void onPath(PolylineOptions polyLine);
}

在活动或片段中使用

ArrayList<LatLng> wayPoint = new ArrayList<>();
GoogleMap mMap;
LatLng source = new LatLng(xx.xxxx, yy.yyyy);
LatLng destination = new LatLng(xx.xxxx, yy.yyyy);

new GetPathFromLocation(context, source, destination, wayPoint, mMap, true, false, new DirectionPointListener() {
        @Override
        public void onPath(PolylineOptions polyLine) {
            mMap.addPolyline(polyLine);
        }
    }).execute();

strings.xml

<string name="google_api_key_app">Place_Your_API_Key</string>    

答案 2 :(得分:0)

您也可以绘制不带折线的路线。使用Google Maps Projection API,您可以将其绘制在覆盖层上。查看repo为例。

enter image description here

答案 3 :(得分:0)

几周前我不得不这样做,但是这些答案都没有达到我的目标。我有一个点列表,每个点之间的距离在150m <1000m之间,并且想要所有点之间的平滑动画。

  1. 扩展位置路径以填补较大的空白
fun List<Location>.expandUserPath(): List<Location> {
    var totalDistanceTravelled = 0f
    this.forEachIndexed { index, location ->
        if (index < this.size - 1) {
            totalDistanceTravelled += location.distanceTo(this[index + 1])
        }
    }

    if (totalDistanceTravelled < 20f) totalDistanceTravelled = 20f

    val maxDistanceNeeded = totalDistanceTravelled / 200
    val filledInLocations = this.sortedBy { it.time }.toMutableList()
    var i = 0
    while (i < filledInLocations.size - 1) {
        do {
            val distanceToNextPoint = filledInLocations[i].distanceTo(filledInLocations[i + 1])
            if (distanceToNextPoint > maxDistanceNeeded) {
                val midpoint =  LatLngBounds.builder().include(LatLng(filledInLocations[i].latitude, filledInLocations[i].longitude)).include(LatLng(filledInLocations[i + 1].latitude, filledInLocations[i + 1].longitude)).build().center
                filledInLocations.add(i + 1, midpoint.toLocation())
            }
        } while (distanceToNextPoint > maxDistanceNeeded)
        i++
    }

    return filledInLocations.toList()
}
  1. 通过点动画
val animatedLocations = locations.expandUserPath()
val tAnimator: ValueAnimator = ValueAnimator.ofFloat(0.0f, 1.0f)
tAnimator.interpolator = LinearInterpolator()
tAnimator.duration = if (locations.size < 5) 2000L else 4000L
tAnimator.addUpdateListener {
    if (activity == null) { tAnimator.cancel(); return@addUpdateListener }
    val value = it.animatedValue as? Float ?: 0f
    val indexOfNextPoint = (value * animatedLocations.size).toInt()
    val points = animatedLocations.filterIndexed { index, _ -> index in 0 until indexOfNextPoint }.map { it.toLatLong() }
    setPolyLine(points)
}
tAnimator.start()
  1. 更新地图折线
var polyLine: Polyline? = null
fun setPolyLine(locations: List<LatLng>) {
    polyLine?.let {
        it.points = locations
    } ?: run {
        val polylineOptions = PolylineOptions()
        polylineOptions.width(13f)
        polylineOptions.color(resources.getColor(R.color.lightBlue))
        polylineOptions.addAll(locations)
        polyLine = map?.addPolyline(polylineOptions)
    }
}

希望可以帮助某人制作:dope:动画!

这是动画的一个例子 https://drive.google.com/file/d/1Pof2OjokxJxUS81lxdwJJy2j8B14Fi41/view?usp=sharing

答案 4 :(得分:0)

private void drawRoute()
    {
        mGoogleApiProvider.getDirections(mOrigenLatLng, mDestinoLatLng)
                .enqueue(new Callback<String>()
                         {
                             @Override
                             public void onResponse(Call<String> call, Response<String> response)
                             {
                                 try
                                 {
                                     JSONObject jsonObject = new JSONObject(response.body());
                                     JSONArray jsonArray = jsonObject.getJSONArray("routes");
                                     JSONObject route = jsonArray.getJSONObject(0);
                                     JSONObject polylines = route.getJSONObject("overview_polyline");
                                     String points = polylines.getString("points");
                                     mPolylineList = DecodificarPuntos.decodificarPoly(points);

                                     mPolylineOptions = new PolylineOptions();
                                     mPolylineOptions.width(10f);
                                     mPolylineOptions.color(Color.parseColor("#191a23"));
                                     mPolylineOptions.startCap(new SquareCap());
                                     mPolylineOptions.endCap(new SquareCap());
                                     mPolylineOptions.jointType(ROUND);

                                     mPolylineOptions.addAll(mPolylineList);

                                     blackPolyLine = mMap.addPolyline(mPolylineOptions);


                                     PolylineOptions greyOptions = new PolylineOptions();
                                     greyOptions.width(10f);
                                     greyOptions.color(Color.GRAY);
                                     greyOptions.startCap(new SquareCap());
                                     greyOptions.endCap(new SquareCap());
                                     greyOptions.jointType(ROUND);

                                     greyPolyLine = mMap.addPolyline(greyOptions);

                                     animatePolyLine();

                                 }
                                 catch(Exception e)
                                 {
                                     Log.e("Error: ", Objects.requireNonNull(e.getMessage()));
                                 }

                             }
                             @Override
                             public void onFailure(Call<String> call, Throwable t)
                             {

                             }
                         }
                );
    }

    private void animatePolyLine()
    {
        ValueAnimator animator = ValueAnimator.ofInt(0, 100);
        animator.setDuration(1000);
        animator.setInterpolator(new LinearInterpolator());
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animator) {

                List<LatLng> latLngList = blackPolyLine.getPoints();
                int initialPointSize = latLngList.size();
                int animatedValue = (int) animator.getAnimatedValue();
                int newPoints = (animatedValue * mPolylineList.size()) / 100;

                if (initialPointSize < newPoints ) {
                    latLngList.addAll(mPolylineList.subList(initialPointSize, newPoints));
                    blackPolyLine.setPoints(latLngList);
                }


            }
        });

        animator.addListener(polyLineAnimationListener);
        animator.start();
    }

    Animator.AnimatorListener polyLineAnimationListener = new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animator) {

            addMarker(mPolylineList.get(mPolylineList.size()-1));
        }

        @Override
        public void onAnimationEnd(Animator animator)
        {
            List<LatLng> blackLatLng = blackPolyLine.getPoints();
            List<LatLng> greyLatLng = greyPolyLine.getPoints();

            greyLatLng.clear();
            greyLatLng.addAll(blackLatLng);
            blackLatLng.clear();

            blackPolyLine.setPoints(blackLatLng);
            greyPolyLine.setPoints(greyLatLng);

            blackPolyLine.setZIndex(2);

            animator.start();
        }

        @Override
        public void onAnimationCancel(Animator animator)
        {
        }

        @Override
        public void onAnimationRepeat(Animator animator)
        {
        }
    };

    private void addMarker(LatLng destination) {

        MarkerOptions options = new MarkerOptions()
                .position(destination)
                .draggable(false)
                .flat(false)
                .icon(BitmapDescriptorFactory.fromBitmap(marcadorPersonalizadoDestino("Destino", mExtraDestino,
                        mExtraTiempo, mExtraTipoDeTiempo, mExtraDistancia, mExtraTipoDeDistancia)
                ));

        mMap.addMarker(options);

    }