当我从A点在地图上绘制折线时 - > B,我要求用动画绘制折线。好像来自A-> B折线继续绘制。
我使用以下链接作为参考:
https://github.com/amalChandran/google-maps-route-animation
使用该解决方案,我能够为折线设置动画,但折线本身并不合适。它没有通过道路。解决方案的原始APK也有同样的错误。
有人可以帮我找一个合适的解决方案
答案 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为例。
答案 3 :(得分:0)
几周前我不得不这样做,但是这些答案都没有达到我的目标。我有一个点列表,每个点之间的距离在150m <1000m之间,并且想要所有点之间的平滑动画。
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()
}
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()
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);
}