Uber Android와 같이지도에서 마커 회전 및 애니메이션 이동
UBER, Lyft 또는 OLA와 유사한 프로젝트를 진행 중입니다. 사용 가능한 움직이는 자동차와 함께 집에지도. 저는 자동차를 UBER처럼 원활하게 움직이고 회전 할 수있는 일종의 라이브러리를 찾고 있습니다. 지금은 아래 코드를 사용하여 한 위도에서 다른 위도에서 자동차로 원활하게 이동할 수있었습니다. 하지만 까다로운 부분은 방향을 바꾸고 방향으로 이동할 때 차가 앞을 향하도록하는 것입니다.
부드러운 움직이는 자동차 코드 :
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();
}
나는 최근에 같은 사용 사례를 보았습니다. 여기에 내 해결책이 있습니다.
먼저 "The Smooth Moving Car Code"를 공유 해주신 @VipiN에게 감사드립니다. 원활하게 작동합니다.
두 번째 부분은 자동차 마커를 올바른 방향으로 배치하고 회전에 따라 회전하는 것입니다. 이를 위해 두 개의 연속 지점 (즉, 장치 / 서버에서받는 위치 업데이트) 사이의 방위 또는 방향 각도를 계산했습니다. 이 링크 는 그 뒤에있는 수학을 이해하는 데 도움 이 됩니다.
다음 코드는 두 위치 사이의 방향을 제공합니다.
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;
}
}
});
}
}
건배!
다음은 uber와 같은 마커를 이동하는 코드입니다. 나는 마커를 이동하는 두 가지 방법을 보여 주었다.
중요 사항 : 적절한 도로 [예 : ola, uber]로 자동차를 이동하려면 Google에서 제공하는 도로 API를 사용해야합니다.
1. 정적 위도 및 경도 기준
2. 실시간 위도와 경도로
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;
}
}
SO 사용자가 두 개의 다른 게시물에서 작업 코드를 찾는 것이 약간 혼란 스러웠 기 때문에. 다음은 나를 위해 원활하게 작동하는 Rotate and Move Marker 의 작업 코드입니다 .
에서 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);
}
}
}
});
}
마지막으로 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);
}
});
}
Firstly,I would like to thank you both @Vipin Negi & @Prasad for such a good & awesomely working code.Since there are many pending queries above, I want to make all the above stuff a little simpler. Guys, just follow the following steps to achieve the marker rotation.
1. Define below two methods in your MainActivity.java file
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) {
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() {
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);
}
}
});
}
2. After this, add the following lines to the code where you want your marker to rotate.
double bearing = bearingBetweenLocations(m.getPosition(), updatedLatLng);
rotateMarker(m, (float) bearing);
Note that "m" is your marker object that you want to rotate. And, you're done!!!
If you want marker animation related help,you can use this code.
ReferenceURL : https://stackoverflow.com/questions/35554796/rotate-marker-and-move-animation-on-map-like-uber-android
'programing' 카테고리의 다른 글
인수가없는 생성자가있는 객체를 std :: map에 배치하는 방법은 무엇입니까? (0) | 2021.01.15 |
---|---|
적용에서 이전 값도 계산 될 때 Pandas에서 dataframe.apply의 이전 행 값을 사용하는 방법이 있습니까? (0) | 2021.01.15 |
C ++, C로 Android 프로그래밍을 할 수 있습니까? (0) | 2021.01.15 |
세션 변수에 대한 제한이 있습니까? (0) | 2021.01.15 |
Mac OS X 10.6.7 Java 경로 현재 JDK 혼동 (0) | 2021.01.15 |