Подтвердить что ты не робот

Поворот маркера и перенос анимации на карту, например, Uber Android

Я работаю над проектом, похожим на UBER, Lyft или OLA, т.е. Карта на дому с имеющимися движущимися автомобилями. Я ищу какую-то библиотеку, которая может заставить Автомобили двигаться и плавно поворачиваться так же, как UBER. На данный момент я смог легко перемещать автомобиль с одного лат-длинного на другой с помощью кода ниже. Но сложной частью является поворот и убедитесь, что автомобиль движется лицом вперед, двигаясь в направлении.

Smooth Moving Car Code:

    final LatLng SomePos = new LatLng(12.7796354, 77.4159606);

    try {
        if (googleMap == null) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
                googleMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
            }
        }
        googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
        googleMap.setMyLocationEnabled(true);
        googleMap.setTrafficEnabled(false);
        googleMap.setIndoorEnabled(false);
        googleMap.setBuildingsEnabled(true);
        googleMap.getUiSettings().setZoomControlsEnabled(true);
        googleMap.moveCamera(CameraUpdateFactory.newLatLng(SomePos));
        googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder()
                .target(googleMap.getCameraPosition().target)
                .zoom(17)
                .bearing(30)
                .tilt(45)
                .build()));

        myMarker = googleMap.addMarker(new MarkerOptions()
                .position(SomePos)
                .icon(BitmapDescriptorFactory.fromResource(R.mipmap.ic_launcher))
                .title("Hello world"));


        googleMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
            @Override
            public boolean onMarkerClick(Marker arg0) {

                final LatLng startPosition = myMarker.getPosition();
                final LatLng finalPosition = new LatLng(12.7801569, 77.4148528);
                final Handler handler = new Handler();
                final long start = SystemClock.uptimeMillis();
                final Interpolator interpolator = new AccelerateDecelerateInterpolator();
                final float durationInMs = 3000;
                final boolean hideMarker = false;

                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;

                        LatLng currentPosition = new LatLng(
                                startPosition.latitude * (1 - t) + finalPosition.latitude * t,
                                startPosition.longitude * (1 - t) + finalPosition.longitude * t);

                        myMarker.setPosition(currentPosition);

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

                return true;

            }

        });

    } catch (Exception e) {
        e.printStackTrace();
    }
4b9b3361

Ответ 1

Недавно я столкнулся с одним и тем же случаем. Вот мое решение.

Во-первых, я хотел бы поблагодарить @VipiN за то, что он поделился "Гладким Moving Car Code". Он работает плавно.

Вторая часть - разместить маркер автомобиля в правильном направлении и повернуть его в соответствии с поворотами. Для этого я вычислил угол подшипника или заголовка между двумя последовательными точками (например, обновлениями местоположения, которые вы получаете с устройства/сервера). Эта ссылка поможет вам понять математику позади нее.

Следующий код даст вам опору между двумя местоположениями:

private double bearingBetweenLocations(LatLng latLng1,LatLng latLng2) {

    double PI = 3.14159;
    double lat1 = latLng1.latitude * PI / 180;
    double long1 = latLng1.longitude * PI / 180;
    double lat2 = latLng2.latitude * PI / 180;
    double long2 = latLng2.longitude * PI / 180;

    double dLon = (long2 - long1);

    double y = Math.sin(dLon) * Math.cos(lat2);
    double x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1)
            * Math.cos(lat2) * Math.cos(dLon);

    double brng = Math.atan2(y, x);

    brng = Math.toDegrees(brng);
    brng = (brng + 360) % 360;

    return brng;
}

Наконец, нам нужно повернуть маркер автомобиля на угол, который мы получаем из вышеприведенного метода.

private void rotateMarker(final Marker marker, final float toRotation) {
    if(!isMarkerRotating) {
        final Handler handler = new Handler();
        final long start = SystemClock.uptimeMillis();
        final float startRotation = marker.getRotation();
        final long duration = 1000;

        final Interpolator interpolator = new LinearInterpolator();

        handler.post(new Runnable() {
            @Override
            public void run() {
                isMarkerRotating = true;

                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);
                } else {
                    isMarkerRotating = false;
                }
            }
        });
    }
}

Ура!

Ответ 2

С тех пор, как он стал путать пользователей SO, искать рабочий код в двух разных сообщениях. Вот рабочий код для Поворот и перемещение маркера, который без проблем работал у меня.

в MainActivity.java

public void rotateMarker(final Marker marker, final float toRotation, final float st) {
    final Handler handler = new Handler();
    final long start = SystemClock.uptimeMillis();
    final float startRotation = st;
    final long duration = 1555;

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


public void animateMarker(final LatLng toPosition,final boolean hideMarke) {
    final Handler handler = new Handler();
    final long start = SystemClock.uptimeMillis();
    Projection proj = googleMap.getProjection();
    Point startPoint = proj.toScreenLocation(m.getPosition());
    final LatLng startLatLng = proj.fromScreenLocation(startPoint);
    final long duration = 5000;

    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);
            double lng = t * toPosition.longitude + (1 - t)
                    * startLatLng.longitude;
            double lat = t * toPosition.latitude + (1 - t)
                    * startLatLng.latitude;
            m.setPosition(new LatLng(lat, lng));

            if (t < 1.0) {
                // Post again 16ms later.
                handler.postDelayed(this, 16);
            } else {
                if (hideMarke) {
                    m.setVisible(false);
                } else {
                    m.setVisible(true);
                }
            }
        }
    });
}

Ответ 3

Вот мой код для перемещения маркера, например, uber. Я показал два способа перемещения маркера.

Важное примечание. Чтобы переместить автомобиль на правильной дороге [например, ola, uber], вам нужно использовать road api, предоставленный google

1. Статическая широта и долгота

2.By Локатор и долгота в режиме реального времени

package com.gangsofcoder.googlemapdemo;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.PersistableBundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.animation.LinearInterpolator;
import android.widget.Button;
import android.widget.Toast;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.RequestParams;

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

import java.util.ArrayList;

import cz.msebera.android.httpclient.Header;

public class MoveCar extends AppCompatActivity {
    private GoogleMap googleMap;
    SupportMapFragment mapFragment;
    Marker marker;
    private boolean isMarkerRotating = false;
    ArrayList<LatLng> listOfPoints = new ArrayList<>();
    int currentPt = 0;
    LatLng finalPosition;
    Marker mMarker;

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    setUpMapIfNeeded();
    //new location details
    listOfPoints.add(new LatLng(30.701623, 76.684220));
    listOfPoints.add(new LatLng(30.702486, 76.685487));
    listOfPoints.add(new LatLng(30.703135, 76.684891));
    listOfPoints.add(new LatLng(30.703256, 76.685000));
    listOfPoints.add(new LatLng(30.703883, 76.685941));
    listOfPoints.add(new LatLng(30.703413, 76.685190));
}

private void setUpMapIfNeeded() {
    if (mapFragment == null) {
        mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);

        if (mapFragment != null) {
            mapFragment.getMapAsync(new OnMapReadyCallback() {
                @Override
                public void onMapReady(GoogleMap googleMap) {
                    loadMap(googleMap);
                }
            });
        }
    }
}

private void loadMap(GoogleMap map) {
    googleMap = map;

    mMarker = googleMap.addMarker(new MarkerOptions().position(new LatLng(30.701623, 76.684220)).icon(BitmapDescriptorFactory.fromResource(R.drawable.icon_car)));      


    final Handler handler = new Handler();
    //Code to move car along static latitude and longitude

  /*  handler.postDelayed(new Runnable() {
        @Override
        public void run() {

            if (currentPt < listOfPoints.size()) {
                //post again
                Log.d("tess", "inside run ");
                Location targetLocation = new Location(LocationManager.GPS_PROVIDER);
                targetLocation.setLatitude(listOfPoints.get(currentPt).latitude);
                targetLocation.setLongitude(listOfPoints.get(currentPt).longitude);
                animateMarkerNew(targetLocation, mMarker);
                handler.postDelayed(this, 3000);
                currentPt++;
            } else {
                Log.d("tess", "call back removed");
                //removed callbacks
                handler.removeCallbacks(this);
            }
        }
    }, 3000);*/

    //Here move marker along real time updates
    final RequestParams params = new RequestParams();
    params.put("source_lattitude", "lat");
    params.put("source_longitude", "long");
    params.put("date", "date");

    //new handler
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {

            LoopjHttpClient.post(getString(R.string.default_upload_website), params, new AsyncHttpResponseHandler() {
                @Override
                public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {

                    try {
                        JSONObject jsonObject = new JSONObject(new String(responseBody));
                        String status = jsonObject.getString("status");
                        String text = jsonObject.getString("text");
                        //reading json array
                        JSONArray jsonArray = jsonObject.getJSONArray("result");
                        String source = jsonArray.getJSONObject(0).getString("source");

                        String[] latLong = source.split(",");
                        Location location = new Location(LocationManager.GPS_PROVIDER);
                        location.setLatitude(Double.parseDouble(latLong[0]));
                        location.setLongitude(Double.parseDouble(latLong[1]));
                        //calling method to animate marker  
                        animateMarkerNew(location, mMarker);
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
                    Log.d("onFailure", "onFailure");
                }
            });

            handler.postDelayed(this, 3000);
        }
    }, 3000);

}

private void animateMarkerNew(final Location destination, final Marker marker) {

    if (marker != null) {

                final LatLng startPosition = marker.getPosition();
                final LatLng endPosition = new LatLng(destination.getLatitude(), destination.getLongitude());

                final float startRotation = marker.getRotation();
                final LatLngInterpolatorNew latLngInterpolator = new LatLngInterpolatorNew.LinearFixed();

                ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
                valueAnimator.setDuration(3000); // duration 3 second
                valueAnimator.setInterpolator(new LinearInterpolator());
                valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        try {
                            float v = animation.getAnimatedFraction();
                            LatLng newPosition = latLngInterpolator.interpolate(v, startPosition, endPosition);
                            marker.setPosition(newPosition);
                            googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder()
                                    .target(newPosition)
                                    .zoom(15.5f)
                                    .build()));

                            marker.setRotation(getBearing(startPosition, new LatLng(destination.getLatitude(), destination.getLongitude())));
                        } catch (Exception ex) {
                            //I don't care atm..
                        }
                    }
                });
                valueAnimator.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        super.onAnimationEnd(animation);

                        // if (mMarker != null) {
                            // mMarker.remove();
                        // }
                        // mMarker = googleMap.addMarker(new MarkerOptions().position(endPosition).icon(BitmapDescriptorFactory.fromResource(R.drawable.icon_car)));

                    }
                });
                valueAnimator.start();
    }
}

private interface LatLngInterpolatorNew {
    LatLng interpolate(float fraction, LatLng a, LatLng b);

    class LinearFixed implements LatLngInterpolatorNew {
        @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);
        }
    }
}


//Method for finding bearing between two points
private float getBearing(LatLng begin, LatLng end) {
    double lat = Math.abs(begin.latitude - end.latitude);
    double lng = Math.abs(begin.longitude - end.longitude);

    if (begin.latitude < end.latitude && begin.longitude < end.longitude)
        return (float) (Math.toDegrees(Math.atan(lng / lat)));
    else if (begin.latitude >= end.latitude && begin.longitude < end.longitude)
        return (float) ((90 - Math.toDegrees(Math.atan(lng / lat))) + 90);
    else if (begin.latitude >= end.latitude && begin.longitude >= end.longitude)
        return (float) (Math.toDegrees(Math.atan(lng / lat)) + 180);
    else if (begin.latitude < end.latitude && begin.longitude >= end.longitude)
        return (float) ((90 - Math.toDegrees(Math.atan(lng / lat))) + 270);
    return -1;
}

}

Ответ 4

UberCarAnimation - это Android-библиотека, которая показывает движение автомобиля на карте, как в Uber.

API и библиотеки, которые необходимо использовать для реализации анимации Uber Car:

  • Карты Google Api
  • API-интерфейс Google Maps Directions
  • Volley

tellmehow

Разберите " overview_polyline" из JSON, предоставив соответствующие параметры GET. Например,

"https://maps.googleapis.com/maps/api/directions/json?" +
                    "mode=driving&"
                    + "transit_routing_preference=less_driving&"
                    + "origin=" + latitude + "," + longitude + "&"
                    + "destination=" + destination + "&"
                    + "key=" + getResources().getString(R.string.google_directions_key)

Расшифруйте полилинию, которая предоставит вам список широт и долгот, который Список будет подходящим.

Создайте аниматор значений, указав ofFloatValue, установив продолжительность и добавив прослушиватель обновлений в Handler

ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
valueAnimator.setDuration(3000);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  @Override
  public void onAnimationUpdate(ValueAnimator valueAnimator) {
    //CODE
});

В аниматоре обновлений анимации Update получите фрагмент анимации и оцените широты и долготы, как показано:

v=valueAnimator.getAnimatedFraction();
lng = v * endPosition.longitude + (1 - v)* startPosition.longitude;
lat = v * endPosition.latitude + (1 - v)* startPosition.latitude;

где v - фракция анимации, а начальная позиция и endPostion относятся к каждой паре LatLng из декодированного списка из полилинии, например, (0,1), затем (1,2), затем (2,3) и т.д.

Наконец, установите положение маркера в новое положение, а также оцените опору между последовательными точками, чтобы автомобиль казался буквально и, наконец, обновлял камеру как:

marker.setPosition(newPos);
marker.setAnchor(0.5f, 0.5f);
marker.setRotation(getBearing(startPosition, newPos));
mMap.moveCamera(CameraUpdateFactory
                .newCameraPosition
                (new CameraPosition.Builder()
                target(newPos)
                .zoom(15.5f)
                .build()));

В приложении используется Google Maps Api Key и Google Maps Directions. Получите эти ключи api на консоли Google для разработчиков, включив их для своего проекта. Замените api ключ google maps в файле strings.xml и google maps в google_maps_api.xml.

Ответ 5

Наконец написал код, который работает точно так же, как OLA CABS делает...

Вот он -

  • Поместите ваш фрагмент карты Google в Относительный макет и поместите маркер (как изображение) в центр -

  • В коде фрагмента, когда вы настроили все основные рабочие страницы Google, напишите следующий код для функции onMapReady (GoogleMap googleMap) -

Мой код выглядит следующим образом:

//Шаг 1 -

 <RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">



<fragment
    android:id="@+id/map"
    android:name="com.google.android.gms.maps.SupportMapFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MapsActivity_for_request_pages" />

    <ImageView
        android:layout_width="30sp"
        android:layout_height="30sp"
        android:layout_centerInParent="true"
        android:id="@+id/central_marker"
        android:src="@drawable/marker_pic"/>

</RelativeLayout>

//Шаг 2 -

@Override
public void onMapReady(GoogleMap googleMap) {


     central_marker = (ImageView)v.findViewById(R.id.central_marker);
     int init_loc = 0,final_loc = -300;
     mMap = googleMap;

 final  CountDownTimer timer = new CountDownTimer(300,300) {
       @Override
       public void onTick(long millisUntilFinished) {

       }

       @Override
       public void onFinish() {
           init_loc = 0;
           ObjectAnimator objectAnimatorY = ObjectAnimator.ofFloat(central_marker, "translationY", final_loc, init_loc);
           objectAnimatorY.setDuration(200);
           objectAnimatorY.start();
       }
   };


    mMap.setOnCameraMoveStartedListener(new GoogleMap.OnCameraMoveStartedListener() {
        @Override
        public void onCameraMoveStarted(int i) {

            System.out.println("Camera started moving worked");
            timer.cancel();
            ObjectAnimator objectAnimatorY = ObjectAnimator.ofFloat(central_marker, "translationY", init_loc, final_loc);
            objectAnimatorY.setDuration(200);
            objectAnimatorY.start();
            init_loc = -300;

        }
    });



    mMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
        @Override
        public void onCameraIdle() {
            System.out.println("Camera idle worked");
            if(initial_flag!=0)
            {
                System.out.println("Camera Setting timer now");
                timer.cancel();
                timer.start();
            }
            initial_flag++;
            System.out.println("Camera Value of initial_flag ="+initial_flag);
        }
    });

}

Ответ 6

Это базовая реализация Tracker Location Tracker с использованием API Карт Google. Внедряет Listening List для получения периодических обновлений движений и анимирует указатель карты, аналогичный приложению Uber.

введите описание изображения здесь

https://github.com/frankodoom/MotionVehicleTracker