[iOS] NaverMap - 화면 가운데 고정된 마커 설정 및 좌표 반환

이번 글은 프로젝트를 진행하며 내가 알아내고 구현한 것 위주로 서술하였다. 다른 더 좋은 방법이 있을 수도 있다!

 

 

 

화면 가운데 마커 설정하기

택시 호출 앱 등을 살펴보면 화면 정 가운데 마커가 있고,

화면을 드래그하면 드래그가 끝났을 때, 현 위치 주소가 바뀌는 것을 본적이 있을 것이다.

이번 글에선 이 기능에 대해 설명해보려한다.

 

 

 

 

마커 만들기

우선 간단하게 마커를 찍는 방법부터 알아보자면 

 

import UIKit
import NMapsMap

class CenterMarkerViewController: UIViewController, NMFMapViewCameraDelegate {
    
    let centerMarker = NMFMarker()
    
    override func viewDidLoad() {
        super.viewDidLoad()

        let naverMap = NMFNaverMapView(frame: view.frame)
        view.addSubview(naverMap)
        
        centerMarker.position = naverMap.mapView.cameraPosition.target //지도 화면 가운데 위치
        centerMarker.captionText = "마커"
        centerMarker.captionAligns = [NMFAlignType.top] //캡션의 위치
        centerMarker.mapView = naverMap.mapView //마커 지도에 추가
    }

}

 

위와 같이 NMFMarker 객체를 추가해 주고,

position을 지정해 준 뒤 지도에 추가해주면추가해 주면 끝이다.

그 외에 여러 옵션들은 필요하다면 추가해 주면 된다.

 

 

 

 

Delegate 살펴보기

 

이제 여기서 카카오 T나 여러 택시앱들처럼 지도를 드래그해도 마커는 화면 가운데에 고정되게 해 보자.

 

화면 가운데 마커를 구현하기 위해서는 Delegate를 이용해야 한다.

naverMap.mapView.addCameraDelegate(delegate: self)

 

간단하게 메서드를 톺아보자면

 

1. Camera Is Chaing By Reason 메서드

  • 지도 화면이 움직였을 때 호출되는 메서드로 코드로 카메라 위치가 바뀌든, 드래그를 통해 바뀌든 상관없이 호출된다.  
  • 매개변수로 주어지는 Reason을 통해 왜 지도뷰가 이동했는지 알 수 있다.
    • NMFMapChangedByDeveloper는 코드로 화면이 움직였을 때 (기본값)
    • NMFMapChangedByGesture는 사용자의 드래그로 화면이 움직였을 때
    • NMFMapChangedByControl는 버튼 선택으로 화면이 움직였을 때
    • NMFMapChangedByLocation은 네이버 지도가 제공하는 위치 트래킹 기능으로 화면이 움직였을 때
  • 만약 이 메서드가 없다면 사용자가 드레그를 빠르게 하고 손을 놓아버렸을 때 마커가 따라오지 않게 된다.(빠르게 드래그하고 손을 놓아도 움직임이 계속되는 것을 관성 드래깅이라고 한다.) 그 후 이동이 끝나면 마커가 따라오게 되는데, 마커가 따라오지 않아 사용자가 불편함을 느낄 수 있는 부분이다.

 

 

 

 

2. Camera Did Change By Reason 메서드

  • 지도 화면의 이동을 계속해서 추적하는 메서드이다. 나름대로 추측해 보건대 카메라의 움직임이 끝났을 때라고 나와있는데 드래그로 움직일 때 조금의 이동 자체도 한 움직임이 시작되었다가 끝났다고 인식하는 것 같다. 이 조금의 이동이 연속적으로 있고, 이동이 끝날 때마다(조금씩 이동할 때마다) 호출되는 메서드인 것 같다. 나머지 부분은 위와 같다.
  • 만약 이 메서드가 없다면 드래그 시 마커가 따라오지 않는다. 그 후 드래그가 끝나면 마커가 따라오게 된다.
    • cameraIsChangingByReason 메서드와의 차이점은 cameraIsChangingByReason는 드래그를 빨리 해서 손을 놓았을 때, 아직 화면이 움직이는 상태일 때 따라오지 않는 것이고, 이 메서드는 드래그로 움직였을 때 따라오지 않는 것이다.

 

 

 

 

3. Camera Idle 메서드

  • 카메라의 움직임 즉, 화면 이동이 완전히 끝나면 호출되는 메서드이다.
  • 이 메서드가 없어도 화면 중앙에 마커를 고정시킬 수는 있지만, 이 메서드를 사용해 준다면 드레그를 완료한 시점에 좌표만 손쉽게 얻을 수 있다.

 

 

 

4. 구현 코드

 

이제 코드로 구현을 해보자.

방법은 마커를 만들고

드래그 시 마커가 화면 가운데에 고정되게 position을 계속해서 업데이트해 준다.

마지막으로 이동이 끝났을 때 좌표값을 print 해보겠다.

import UIKit
import NMapsMap

class CenterMarkerViewController: UIViewController, NMFMapViewCameraDelegate {
    
    let centerMarker = NMFMarker()
    
    override func viewDidLoad() {
        super.viewDidLoad()

        let naverMap = NMFNaverMapView(frame: view.frame)
        view.addSubview(naverMap)
        
        let cameraUpdate = NMFCameraUpdate(scrollTo: NMGLatLng(lat: 37.479132, lng: 127.011770))
        naverMap.mapView.moveCamera(cameraUpdate)
        
        centerMarker.position = naverMap.mapView.cameraPosition.target
        centerMarker.captionText = "마커"
        centerMarker.captionAligns = [NMFAlignType.top]
        centerMarker.mapView = naverMap.mapView
        
        naverMap.mapView.addCameraDelegate(delegate: self)
    }
    // 화면 이동을 추적
    func mapView(_ mapView: NMFMapView, cameraIsChangingByReason reason: Int) {
        centerMarker.position = mapView.cameraPosition.target
    }
    // 화면 이동을 추적
    func mapView(_ mapView: NMFMapView, cameraDidChangeByReason reason: Int, animated: Bool) {
        centerMarker.position = mapView.cameraPosition.target
    }
    // 이동이 끝났을 때 좌표값 print
    func mapViewCameraIdle(_ mapView: NMFMapView) {
        print(mapView.cameraPosition.target)
    }

}

 

위와 같이 코딩하면 콘솔 창에 드래그가 끝날 때마다 좌표값이 반환되는 것을 볼 수 있다.

 

 

결과물은 아래와 같다.

 

 

 

 

 

이 기능을 이용하면 <택시팟>에 구현한 기능처럼 Naver Cloud API를 활용해서 실시간으로 주소로 변환도 가능하다.

또 출발점과 도착지점을 설정하면 내비게이션처럼 최적의 길을 표시해주기도 한다.

이 부분은 다음 글에서 다뤄보겠다.