Google Map에 목적지 마커를 추가한 후, 사용자가 해당 마커 위치로 이동할 때마다 남은 거리를 계산 해주도록 작성해보았습니다.
‘
2017. 11. 30 최초작성
~~~~~~~~~
2019. 11. 25 FusedLocationProviderClient로 변경
다음 포스팅에 있는 코드를 기반으로 작성되었습니다.
먼저 아래 코드로 진행해보고 나서 진행하세요..
GenyMotion을 사용하여 Google Map 테스트를 진행했습니다.
자세한 사용 방법은 다음 포스팅을 참고하세요.
현재 위치를 시청역으로 설정했습니다.
![](https://lh4.googleusercontent.com/II9BzY7l1syrzKM2fAnnINIzNZ6OqB3YKo-p_1umIuSUYwTruElJbNizDDRUnKrntwezRpgJbezbjTx6ixolIRkH4rJSDSYC6hDETg7O7ouWeaJIoHPa52rN2pEvI6FW0xBUpZm5)
목적지가 될 회현역에 마커를 추가하기 위해서 오랫동안 클릭하면 다음처럼 다이얼로그 창이 뜹니다.
마커 클릭시 보여줄 정보를 입력한 후, 완료를 클릭합니다.
![](https://lh3.googleusercontent.com/2cr3nJF_znIatjK2j1KVNYluyMX8FjkZMoUuauusa36zUr4TaklncRgcDGPFQLUey6OTf4dxP1b9biGp2ksDKKVyaxagFAzLPWZXHzekJ2JONSunVIQ1ZcL_aKbxIWleAdAzvD-m)
빨간색 마커가 추가되며 클릭해보면 좀전에 입력했던 정보를 보여줍니다.
![](https://lh6.googleusercontent.com/ri0EZePYu0_KkrqYzyVN3lPFDpocJ-SWcHBdDVNUGKLzRdFSR3Zf94gLe90jKJAJAm8IcyAUR5MaHQ-21Aa_ZRyly3cRtWT1JIz_HDjpuBtbVa-xQuXhwXvIDWRYJUyckGLpEd3F)
앱 하단의 버튼을 클릭하면 현재 위치와 목적지 마커 사이의 거리 계산을 시작합니다.
![](https://lh5.googleusercontent.com/L9A7KYE4-fDuQXcPxQjAn5aTBiCHXFaBw1kocmT1MRTVpuKdjfNc_C2DO1FzwbjY94TxVGvlqsKBO3lJf1twiB6u_-WZxWSxa7psnJx3_3J7uzb-WAWbWELY_TERj1XslZ48q09L)
현재 위치를 이동시키면 회현역까지 몇미터 남았는지 알려줍니다.
(목적지와의 거리가 몇미터 이내이면 도착으로 할지 결정해서 이후 코딩을 진행하시면 될 듯합니다. )
![](https://lh5.googleusercontent.com/iv84zNSqDeicoEM2kv29mOEz45oXLY2dUyufyFbM0siHmhYWwE97NmX278XHIvii7s0murrMIYXL5cZhnRYpnCZUQvWLwEMUlIKq6aWXi72eDEhrQGWZ6QhiUT44DAzwMSHe8mRU)
목적지와 현재 위치간의 거리 계산을 위해서 SphericalUtil의 computeDistanceBetween 메소드를 사용했습니다.
double computeDistanceBetween(LatLng from, LatLng to) |
다음처럼 코드 수정을 진행합니다.
1. SphericalUtil를 사용하기 위해서는 build.gradle에 다음 한 줄을 추가해야 합니다.
dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'androidx.appcompat:appcompat:1.0.2' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'com.google.android.gms:play-services-maps:17.0.0' implementation 'com.google.android.gms:play-services-location:17.0.0' implementation 'com.google.android.material:material:1.1.0-alpha09' implementation 'com.google.maps.android:android-maps-utils:0.5' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' } |
2. 다음처럼 3개의 변수를 선언합니다.
Location mCurrentLocatiion; LatLng currentPosition; LatLng previousPosition = null; Marker addedMarker = null; int tracking = 0; |
3. locationCallback에서 이전 위치와 현재 위치가 다른 경우 (!previousPosition.equals(currentPosition))
정해진 목적지까지의 거리인 500미터이내에 있고(distance < radius) 트래킹 설정 중이고 (tracking == 1)
목적지 마커가 설정되어 있다면 (addedMarker != null)
Toast.makeText 메소드를 사용하여 현재위치와 목적지 사이의 거리를 출력해줍니다.
거리 계산에는 SphericalUtil.computeDistanceBetween 메소드를 사용했습니다.
LocationCallback locationCallback = new LocationCallback() { @Override public void onLocationResult(LocationResult locationResult) { super.onLocationResult(locationResult);
List<Location> locationList = locationResult.getLocations();
if (locationList.size() > 0) { location = locationList.get(locationList.size() - 1);
previousPosition = currentPosition;
currentPosition = new LatLng(location.getLatitude(), location.getLongitude());
if (previousPosition == null) previousPosition = currentPosition;
if ( (addedMarker != null) && tracking == 1 ) { double radius = 500; // 500m distance.
double distance = SphericalUtil.computeDistanceBetween(currentPosition, addedMarker.getPosition());
if ((distance < radius) && (!previousPosition.equals(currentPosition))) {
Toast.makeText(MainActivity.this, addedMarker.getTitle() + "까지" + (int) distance + "m 남음", Toast.LENGTH_LONG).show(); } }
String markerTitle = getCurrentAddress(currentPosition); String markerSnippet = "위도:" + String.valueOf(location.getLatitude()) + " 경도:" + String.valueOf(location.getLongitude());
Log.d(TAG, "onLocationResult : " + markerSnippet);
//현재 위치에 마커 생성하고 이동 setCurrentLocation(location, markerTitle, markerSnippet);
mCurrentLocatiion = location; }
}
}; |
4. 원하는 위치를 사용자가 길게 클릭했을 경우 마커를 추가하기 위해서 onMapReady 메서드에 다음 코드를 추가합니다.
@Override public void onMapReady(final GoogleMap googleMap) { Log.d(TAG, "onMapReady :");
mMap = googleMap;
mMap.setOnMapLongClickListener(new GoogleMap.OnMapLongClickListener(){
@Override public void onMapLongClick(final LatLng latLng) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); LayoutInflater inflater = getLayoutInflater(); View view = inflater.inflate(R.layout.dialog_place_info, null); builder.setView(view); final Button button_submit = (Button) view.findViewById(R.id.button_dialog_placeInfo); final EditText editText_placeTitle = (EditText) view.findViewById(R.id.editText_dialog_placeTitle); final EditText editText_placeDesc = (EditText) view.findViewById(R.id.editText_dialog_placeDesc);
final AlertDialog dialog = builder.create(); button_submit.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { String string_placeTitle = editText_placeTitle.getText().toString(); String string_placeDesc = editText_placeDesc.getText().toString(); Toast.makeText(MainActivity.this, string_placeTitle+"\n"+string_placeDesc,Toast.LENGTH_SHORT).show();
//맵을 클릭시 현재 위치에 마커 추가 MarkerOptions markerOptions = new MarkerOptions(); markerOptions.position(latLng); markerOptions.title(string_placeTitle); markerOptions.snippet(string_placeDesc); markerOptions.draggable(true); markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED));
if ( addedMarker != null ) mMap.clear(); addedMarker = mMap.addMarker(markerOptions);
dialog.dismiss(); } });
dialog.show();
} }); |
5. 위 코드에서 사용한 커스텀 다이얼로그를 위해 레이아웃 파일을 다음처럼 작성합니다.
dialog_place_info.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent">
<TextView android:id="@+id/textView_dialog_placeTitle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_alignParentTop="true" android:layout_marginLeft="22dp" android:layout_marginStart="22dp" android:layout_marginTop="26dp" android:text="장소 이름" />
<EditText android:id="@+id/editText_dialog_placeTitle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_marginLeft="37dp" android:layout_marginStart="37dp" android:layout_marginTop="16dp" android:layout_toEndOf="@+id/textView_dialog_placeTitle" android:layout_toRightOf="@+id/textView_dialog_placeTitle" android:ems="10" android:inputType="textPersonName" android:text="" />
<TextView android:id="@+id/textView_dialog_placeDesc" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/editText_dialog_placeTitle" android:layout_marginTop="16dp" android:layout_toLeftOf="@+id/editText_dialog_placeTitle" android:layout_toStartOf="@+id/editText_dialog_placeTitle" android:text="장소 설명" />
<EditText android:id="@+id/editText_dialog_placeDesc" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@+id/editText_dialog_placeTitle" android:layout_alignStart="@+id/editText_dialog_placeTitle" android:layout_below="@+id/editText_dialog_placeTitle" android:ems="10" android:inputType="textPersonName" android:text="" />
<Button android:id="@+id/button_dialog_placeInfo" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignEnd="@+id/editText_dialog_placeDesc" android:layout_alignRight="@+id/editText_dialog_placeDesc" android:layout_below="@+id/editText_dialog_placeDesc" android:layout_marginTop="26dp" android:text="완료" />
</RelativeLayout> |
![](https://lh6.googleusercontent.com/XGrWUbiEdAt5P1_Hxc3vgtjNaWWclgNGiunbpOrzCAqk_nO7giWQa-z-yWZdBau26UMeyOs-zdz9l6JneB7QczVuwMngGc7LHmD6h_eouGzT3FyHAoEf5Pp4Lb-diNBKYQw5v2MV)
6. 사용자의 현재 위치와 목적지간의 거리 계산을 시작 또는 중지하기 위한 버튼을 지도 아래에 추가해줍니다.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/layout_main" android:orientation="vertical" tools:context=".MainActivity" >
<fragment android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="9" android:id="@+id/map" tools:context=".MapsActivity" android:name="com.google.android.gms.maps.SupportMapFragment" />
<Button android:id="@+id/button" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:text="Start" />
</LinearLayout> |
![](https://lh3.googleusercontent.com/5kWdy-G3SwEnU2ukfWftna0nx-_0vnEbLYOgI7S5k5S3nuiL2pW3u33l09-Cm-7zxcOM8xgFaChIfBvx7Q37x-u8zE4Y7y9bI5iZ-zAKVfVq6xhXPXTGhpi-vZ6ZNGUFYRwxMAbC)
7. MainActivity의 OnCreate 메소드에 다음 코드를 추가합니다.
버튼 클릭시 변경되는 트레킹 여부를 저장하기 위해 int 타입의 tracking 변수를 이용했습니다.
초기값은 0으로 해야합니다.
final Button button = (Button)findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) {
tracking = 1 - tracking;
if ( tracking == 1){ button.setText("Stop"); } else button.setText("Start"); } }); |
이제 테스트를 해보면 됩니다.