본문 바로가기
안드로이드

안드로이드 네이버 지도 사용하기 (Fragment)

by 새로운 도전을 즐기는 모기같은 개발자. 하늘을난모기 2017. 12. 26.

네이버 지도 API를 사용 해보면 알겠지만.. 엄청나게 불편하다.


Fragment에서 사용하는 방법을 위해 엄청난 노가다 끝에 만드는데 성공했다.


1. 라이브러리 추가하기

https://github.com/navermaps/maps.android

가장 최신 버전의 라이브러리를 app단 build.gradle에 추가한다.


(현재 최신)

dependencies {

   compile 'com.naver.maps.open:naver-map-api:2.1.2@aar'

}



2. 필요한 클래스 파일을 만든다.

 - https://github.com/navermaps/maps.android/blob/master/app/src/main/java/com/nhn/android/mapviewer/NMapFragment.java

 - https://github.com/navermaps/maps.android/blob/master/app/src/main/java/com/nhn/android/mapviewer/NMapPOIflagType.java

 - https://github.com/navermaps/maps.android/blob/master/app/src/main/java/com/nhn/android/mapviewer/NMapViewerResourceProvider.java

 - https://github.com/navermaps/maps.android/blob/master/app/src/main/java/com/nhn/android/mapviewer/NMapCalloutCustomOldOverlay.java


이 4개의 클래스 파일을 똑같이 복사하여 넣는다. (패키지를 하나 만들어서 하면 관리가 편하다.)


NMapViewerResourceProvider 클래스만 오류가 날 것이다. (R.drawable 파일이 없어서이다.)


https://github.com/navermaps/maps.android/tree/master/app/src/main/res/drawable-hdpi


이 링크에 있는 아이템을 다운 받아도 된다. 하지만 귀찮으니 일단 R.drawable 부분을 다 주석처리 한다.


NMapViewerResourceProvider 클래스의 351라인을 보면

@Override
public Drawable getCalloutBackground(NMapOverlayItem item) {

if (item instanceof NMapPOIitem) {
NMapPOIitem poiItem = (NMapPOIitem) item;

if (poiItem.showRightButton()) {
Drawable drawable = mContext.getResources().getDrawable(R.drawable.bg_speech);
return drawable;
}
}

Drawable drawable = mContext.getResources().getDrawable(R.drawable.pin_ballon_bg);

return drawable;
}

이런 부분이 있다.

마커를 클릭했을 때 화면에 보여질 말풍선의 백그라운드 배경이다. 원하는 이미지로 넣으면 된다.


우리가 쓸 것은 마커의 시작과 끝이다.

162라인을 보면 이와 같은 부분이 있다.

    // Resource Ids for single icons
private final ResourceIdsOnMap mResourceIdsForMarkerOnMap[] = {
// Spot, Pin icons
// new ResourceIdsOnMap(NMapPOIflagType.PIN, R.drawable.ic_pin_01, R.drawable.ic_pin_02),
// new ResourceIdsOnMap(NMapPOIflagType.SPOT, R.drawable.ic_pin_01, R.drawable.ic_pin_02),

// Direction POI icons: From, To
new ResourceIdsOnMap(NMapPOIflagType.FROM, R.drawable.location_my, R.drawable.location_my),
new ResourceIdsOnMap(NMapPOIflagType.TO, R.drawable.location_t, R.drawable.location_t),
};

FROM은 시작 위치, TO는 마지막 위치다.

원하는 이미지로 바꿔 넣는다.


이후 추가로 아이콘을 더 넣고 싶으면 주석처리 해버린 R.drawable 부분에서 필요한 부분만을 주석을 지우고 그림을 추가하면 된다.

이제 오류를 없앴으니 MapView를 만들자.


public class MapViewFragmentNaver extends NMapFragment 
implements NMapView.OnMapStateChangeListener, NMapPOIdataOverlay.OnStateChangeListener {

이러한 프래그먼트를 만든다.

NMapFragment는 위에 링크에서 NMapFragemnt를 찾아 똑같이 붙여 넣으면 된다.


onMapStateChangeListener()와 OnStateChangeListener()를 상속받고 메서드를 추가한다.


@Override
public void onMapInitHandler(NMapView nMapView, NMapError nMapError) {
if (nMapError == null) {
moveMapCenter();
} else {
Log.e("map init error", nMapError.message);
}
}

상속받은 메서드 중 맵이 초기화 됐을 때의 메서드가 있다.

신기하게도 에러가 null 값 이어야 정상 작동하는 코드다. (가독성이 조금 이상하다.. !=null로 했다가 엄청난 시간을 날려버렸다.....)


이후 onCreateView()함수에 맵 뷰를 초기화 한다.

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_map_view, container, false);
mapView = (NMapView) v.findViewById(R.id.map_view);
mapView.setClientId(getResources().getString(R.string.n_key));
mapView.setClickable(true);
return v;
}

레이아웃의 구성을 잠시 보여주자면..

<?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">

<com.nhn.android.maps.NMapView
android:id="@+id/map_view"
android:layout_width="match_parent"
android:layout_height="match_parent"></com.nhn.android.maps.NMapView>

<LinearLayout
android:layout_width="44dp"
android:layout_height="44dp"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginBottom="16dp"
android:layout_marginRight="16dp"
android:background="@color/colorWhite"
android:gravity="center">

<ImageView
android:id="@+id/img_current_location"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/rectangle_6" />
</LinearLayout>


</RelativeLayout>

이렇다. 별거 없다.

다시 Fragment로 넘어가서


이 클래스에서 가장 중요한 부분은

onStart() 메서드다.


mapVIew()가 생성되는 시기가 이상하기에 onStart()에서 잘 다뤄야 한다.


@Override
public void onStart() {
super.onStart();
mapView.setBuiltInZoomControls(true, null);
mapView.setOnMapStateChangeListener(this);
mapController = mapView.getMapController();
mapViewerResourceProvider = new NMapViewerResourceProvider(getActivity());
mapOverlayManager = new NMapOverlayManager(getActivity(), mapView, mapViewerResourceProvider);
moveMapCenter();
}

onStart() 메서드를 오버라이딩하고 mapView와 관련된 것을 넣는다.


맵을 중앙으로 이동하기 위해 moveMapCenter()라는 메서드를 만들어서 사용했다.

위도와 경도는 다양한 방법으로 얻어올 수 있으니 생략.


private void moveMapCenter() {
NGeoPoint currentPoint = new NGeoPoint(lng, lat);
mapController.setMapCenter(currentPoint);

NMapPOIdata poiData = new NMapPOIdata(2, mapViewerResourceProvider);
poiData.addPOIitem(lng, lat, "현재 위치", NMapPOIflagType.FROM, 0);
poiData.addPOIitem(lng2, lat2, "도착 위치", NMapPOIflagType.TO, 0);
poiData.endPOIdata();

NMapPOIdataOverlay poiDataOverlay = mapOverlayManager.createPOIdataOverlay(poiData, null);
poiDataOverlay.showAllPOIdata(0);
poiDataOverlay.setOnStateChangeListener(this);

}

poiData에서 아이템을 추가하며 Flag 값을 지정하여 어떠한 마커를 사용한지 정한다.

앞서 말했듯이 pin이나 spot 등 다른 마커를 사용하고 싶으면

FROM과 TO 대신 NMapPOIflagType에 있는 다른 flag를 사용하면 된다.


poiDataOverlay.showAllPOIdata(0);

이 메서드를 통해 두 마커가 모두 보이도록 자동으로 카메라의 줌을 조정한다.


단순 맵뷰를 띄우고 마커를 두개 찍어서 보여주는 것이 끝났다.

추가로 길찾기를 만들고 싶다면.. 직접 경로를 다 구해서 마커를 열심히 찍으면 될것이다.

(실제로 네이버 가이드에는 길찾기를 위한 경로 그리기가 모든 경로의 꺽이는 부분을 찾아서 직선으로 연결하고 있다..)

추가 사항은 네이버 API 가이드라인을 참고하자.


https://developers.naver.com/docs/map/tutorial/



진짜... 정말 쓰기 힘든 API다.

레퍼런스도 잘 되어있지 않을 뿐더러.. (lng, lat가 v1, v2로 되어있다 -0-)

검색을 해도 제각기 다른 방식으로 구현하고 있다.


지도가 완성 됐으니 끝.

언젠가는 지금 작성한 노가다보다 쉬운 방법을 찾아 내고 말겠다... (스트레스!!!!!!!!!!!!)

댓글9