사용자 인터페이스

사용자는 컨트롤, 제스처 등 다양한 방법으로 지도와 상호작용할 수 있습니다. 개발자는 사용자가 지도와 상호작용하는 방법을 제어하고, UI 이벤트를 처리해 알맞은 피드백을 줄 수 있습니다.

UI 설정

NMFNaverMapView는 지도에서 사용되는 다양한 컨트롤 UI를 미리 구현한 맵뷰 클래스입니다. NMFNaverMapView의 속성을 변경하면 컨트롤, 사용자 위치 추적 변경 등 UI와 관련된 요소를 제어할 수 있습니다.

컨트롤

컨트롤은 지도에 대한 정보 및 간단한 조작 기능을 제공하는 지도 위 버튼을 의미합니다. 네이버 지도 SDK는 다음과 같은 여섯 가지 컨트롤을 제공합니다.

  • 나침반: 카메라의 회전 및 틸트 상태를 표현합니다. 탭하면 카메라의 헤딩과 틸트가 0으로 초기화됩니다. 헤딩과 틸트가 0이 되면 자동으로 사라집니다. showCompass 속성으로 활성화 여부를 지정할 수 있습니다.

    나침반

  • 축척 바: 지도의 축척을 표현합니다. 지도를 조작하는 기능은 없습니다. showScaleBar 속성으로 활성화 여부를 지정할 수 있습니다.

    축척 바

  • 줌 버튼: 탭하면 지도의 줌 레벨을 1씩 증가 또는 감소합니다. showZoomControls 속성으로 활성화 여부를 지정할 수 있습니다.

    줌 버튼

  • 실내지도 층 피커: 노출 중인 실내지도 구역의 층 정보를 표현합니다. 층을 선택하면 해당 층의 실내지도가 노출됩니다. 실내지도가 보이는 상황에만 나타납니다. showIndoorLevelPicker 속성으로 활성화 여부를 지정할 수 있습니다.

    실내지도 층 패널

  • 현위치 버튼: 위치 추적 모드를 표현합니다. 탭하면 모드가 변경됩니다. 자세한 내용은 위치 문서를 참고하세요. showLocationButton 속성으로 활성화 여부를 지정할 수 있습니다.

    현위치 버튼

  • 네이버 로고: 탭하면 범례, 법적 공지, 오픈소스 라이선스를 보여주는 알림창이 열립니다. 네이버 로고는 비활성화할 수 없으나, 위치를 조정하거나 탭을 비활성화할 수는 있습니다. 네이버 지도 SDK를 사용하는 앱은 반드시 네이버 로고가 앱의 UI 요소에 가려지지 않도록 해야 합니다.

    • logoAlign 속성으로 위치를, logoMargin 속성으로 마진을 지정해 위치를 조정할 수 있습니다.
    • logoInteractionEnabled 속성으로 탭 활성화 여부를 지정할 수 있습니다. 로고 탭을 비활성화한 앱은 반드시 앱 내에 네이버 지도 SDK의 법적 공지(-showLegalNotice) 및 오픈소스 라이선스(-showOpenSourceLicense)뷰를 보여주는 메뉴를 만들어야 합니다.

    네이버 로고

각 컨트롤러의 속성을 변경하면 활성화 여부를 제어할 수 있습니다. 비활성화된 컨트롤은 화면에서 사라집니다.

다음은 나침반을 비활성화하고 현위치 버튼을 활성화하는 예제입니다.

naverMapView.showCompass = false
naverMapView.showLocationButton = true

Swift

naverMapView.showCompass = false
naverMapView.showLocationButton = true

Objective-C

self.naverMapView.showCompass = NO;
self.naverMapView.showLocationButton = YES;

컨트롤 배치

기본 컨트롤의 위치는 변경할 수 없습니다. 그러나 각 컨트롤은 뷰의 형태로 제공되므로 NMFNaverMapView의 각 컨트롤을 비활성화하고 별도의 컨트롤 뷰를 원하는 위치에 배치할 수 있습니다. 뷰를 레이아웃에 추가하고 mapView 속성에 NMFMapView 객체를 지정하면 컨트롤이 동작합니다.

다음은 기본 줌 컨트롤을 비활성화하고 별도의 줌 컨트롤을 배치하는 예제입니다.

@IBOutlet weak var zoomControlView: NMFZoomControlView!

naverMapView.showZoomControls = false
zoomControlView.mapView = naverMapView.mapView;

Swift

@IBOutlet weak var zoomControlView: NMFZoomControlView!

naverMapView.showZoomControls = false
zoomControlView.mapView = naverMapView.mapView;

Objective-C

@property(nonatomic, weak) IBOutlet NMFZoomControlView *zoomControlView;

self.naverMapView.showZoomControls = NO;
self.zoomControlView.mapView = self.naverMapView.mapView;

제스처

사용자는 탭, 드래그, 핀치 등의 각종 제스처로 카메라를 이동할 수 있습니다. 네이버 지도 SDK는 다음과 같은 다섯 가지 제스처를 제공합니다.

  • 스크롤: 한 개 또는 두 개 이상의 손가락으로 지도를 드래그하면 카메라가 손가락을 따라 이동합니다. scrollGestureEnabled 속성으로 활성화 여부를 지정할 수 있습니다.
  • 줌: 지도를 더블 탭하면 줌 레벨이 한 단계 확대됩니다. 두 손가락 탭하면 한 단계 축소됩니다. 핀치와 스트레치 또는 한 손가락 줌 제스처로도 지도의 줌 레벨을 변경할 수 있습니다. zoomGestureEnabled 속성으로 활성화 여부를 지정할 수 있습니다.
  • 틸트: 두 개의 손가락으로 지도를 위아래로 드래그하면 기울임 각도가 바뀝니다. tiltGestureEnabled 속성으로 활성화 여부를 지정할 수 있습니다.
  • 회전: 두 개의 손가락으로 지도를 돌리면 베어링 각도가 바뀝니다. rotateGestureEnabled 속성으로 활성화 여부를 지정할 수 있습니다.
  • 스톱: 카메라 애니메이션이 진행 중일 때 지도를 탭하면 애니메이션이 취소되고 카메라가 현재 위치에 멈춥니다. stopGestureEnabled 속성으로 활성화 여부를 지정할 수 있습니다.

NMFMapView의 속성을 변경하면 각 제스처의 활성화 여부를 제어할 수 있습니다. 만약 사용자에게 기울어지거나 회전되지 않은 지도만을 보여주고자 한다면, 카메라 이동 시 틸트나 헤딩 각도를 지정하지 않는 것뿐만 아니라 제스처 또한 비활성화해서 사용자가 지도를 기울이거나 회전하지 못하도록 해야 합니다.

다음은 틸트와 회전 제스처를 비활성화하는 예제입니다.

mapView.isTiltGestureEnabled = false
mapView.isRotateGestureEnabled = false

Swift

mapView.isTiltGestureEnabled = false
mapView.isRotateGestureEnabled = false

Objective-C

self.mapView.tiltGestureEnabled = NO;
self.mapView.rotateGestureEnabled = NO;

UI 이벤트

네이버 지도 SDK는 사용자의 탭에 반응하는 다양한 UI 이벤트를 제공합니다. 지도의 터치 이벤트는 UIGestureRecognizer를 상속받아 구현되었으므로 제스처 이벤트를 추가할 때 겹치지 않도록 주의해야 합니다.

지도 탭

NMFMapView.touchDelegate 속성에 델리게이트를 지정하면 지도에 대한 탭 및 롱 탭 이벤트를 받을 수 있습니다. 지도를 탭했을 때 -mapView:didTapMap:point 메서드가, 롱 탭했을 때 -mapView:didLongTapMap:point 메서드가 호출되며, 터치된 지점의 화면 좌표와 지도 좌표가 파라미터로 전달됩니다.

다음은 지도를 탭 및 롱 탭했을 때 터치된 지점의 좌표를 표시하는 예제입니다.

func mapView(_ mapView: NMFMapView, didTapMap latlng: NMGLatLng, point: CGPoint) {
    print("탭: \(latlng.lat), \(latlng.lng)")
}

func mapView(_ mapView: NMFMapView, didLongTapMap latlng: NMGLatLng, point: CGPoint) {
    print("롱 탭: \(latlng.lat), \(latlng.lng)")
}

Swift

func mapView(_ mapView: NMFMapView, didTapMap latlng: NMGLatLng, point: CGPoint) {
    print("탭: \(latlng.lat), \(latlng.lng)")
}

func mapView(_ mapView: NMFMapView, didLongTapMap latlng: NMGLatLng, point: CGPoint) {
    print("롱 탭: \(latlng.lat), \(latlng.lng)")
}

Objective-C

- (void)mapView:(NMFMapView *)mapView didTapMap:(NMGLatLng *)latlng point:(CGPoint)point {
    NSLog(@"탭: %f, %f", latlng.lat, latlng.lng);
}

- (void)mapView:(NMFMapView *)mapView didLongTapMap:(NMGLatLng *)latlng point:(CGPoint)point {
    NSLog(@"롱 탭: %f, %f", latlng.lat, latlng.lng);
}

심벌 탭

네이버 지도 SDK는 지도 심벌을 탭한 경우와 지도 자체를 탭한 경우를 구분합니다. 심벌이 탭되면 -mapView:didTapSymbol: 메서드가 호출되며, 탭된 심벌 객체가 파라미터로 전달됩니다. 심벌 객체로부터 탭된 맵뷰 객체와 캡션 텍스트를 얻을 수 있습니다.

심벌 탭 이벤트는 지도로 전파될 수 있습니다. 이벤트를 지도로 전파하려면 NMFMapView-mapView:didTapSymbol:NO를 반환하도록 구현해야 합니다. 그렇게 하면 -mapView:didTapSymbol:이 반환된 후 지도의 -mapView:didTapMap:point가 호출됩니다. 반대로 -mapView:didTapSymbol:YES를 반환할 경우 심벌이 이벤트를 소비한 것으로 간주되어 지도의 -mapView:didTapMap:point는 호출되지 않습니다.

다음은 캡션 텍스트가 "서울특별시청"인 심벌이 탭되면 "서울시청 탭"이라는 로그를, 그 외의 심벌 또는 지도가 탭되면 "지도 탭"이라는 로그를 표시하는 예제입니다.

func mapView(_ mapView: NMFMapView, didTapMap latlng: NMGLatLng, point: CGPoint) {
    print("지도 탭")
}

func mapView(_ mapView: NMFMapView, didTap symbol: NMFSymbol) -> Bool {
    if symbol.caption == "서울특별시청" {
        print("서울시청 탭")
        return true

    } else {
        print("symbol 탭")
        return false
    }
}

Swift

func mapView(_ mapView: NMFMapView, didTapMap latlng: NMGLatLng, point: CGPoint) {
    print("지도 탭")
}

func mapView(_ mapView: NMFMapView, didTap symbol: NMFSymbol) -> Bool {
    if symbol.caption == "서울특별시청" {
        print("서울시청 탭")
        return true

    } else {
        print("symbol 탭")
        return false
    }
}

Objective-C

- (void)mapView:(NMFMapView *)mapView didTapMap:(NMGLatLng *)latlng point:(CGPoint)point {
    NSLog(@"지도 탭");
}

- (BOOL)mapView:(NMFMapView *)mapView didTapSymbol:(NMFSymbol *)symbol {
    if ([symbol.caption isEqualToString:@"서울특별시청"]) {
        NSLog(@"서울시청 탭");
        return YES;
    } else {
        NSLog(@"symbol 탭");
        return NO;
    }
}

오버레이 탭

오버레이도 심벌과 마찬가지로 터치 이벤트를 받고, 이벤트를 소비하거나 전파할 수 있습니다. 오버레이의 터치 이벤트는 지도 또는 심벌 터치 이벤트와 달리 각 오버레이가 받으므로 각 오버레이에 이벤트 핸들러를 등록해야 합니다. 오버레이의 touchHandler 속성에 overlayTouchHandler를 지정하면 오버레이에 대한 터치 이벤트를 받을 수 있습니다. 오버레이가 탭되면 overlayTouchHandler에 기술한 block 메서드가 호출되며, 탭된 오버레이 객체가 파라미터로 전달됩니다.

오버레이의 터치 이벤트는 지도로 전파될 수 있습니다. 이벤트를 지도로 전파하려면 overlayTouchHandlerNO를 반환하도록 구현합니다. 그렇게 하면 block 메서드 실행 후 지도의 -mapView:didTapMap:point가 호출됩니다. 반대로 YES를 반환할 경우 오버레이가 이벤트를 소비한 것으로 간주되어 지도의 -mapView:didTapMap:point는 호출되지 않습니다.

다음은 마커가 탭되면 "마커 터치"라는 로그를 표시하는 예제입니다.

marker.touchHandler = { (overlay: NMFOverlay) -> Bool in
    print("마커 터치")
    return true // 이벤트 소비, -mapView:didTapMap:point 이벤트는 발생하지 않음
}

Swift

marker.touchHandler = { (overlay: NMFOverlay) -> Bool in
    print("마커 터치")
    return true // 이벤트 소비, -mapView:didTapMap:point 이벤트는 발생하지 않음
}

Objective-C

marker.touchHandler = ^BOOL(NMFOverlay *overlay) {
    NSLog(@"마커 터치");
    return YES; // 이벤트 소비, -mapView:didTapMap:point 이벤트는 발생하지 않음
};

오버레이에서 이벤트가 전파되는 곳은 오직 지도뿐입니다. 즉, 이벤트가 발생한 오버레이의 아래에 다른 오버레이나 심벌이 겹쳐져 있더라도 이 오버레이나 심벌로는 이벤트가 전파되지 않습니다. 또한 이벤트 리스너가 등록되지 않은 오버레이는 탭 시 무시됩니다. 즉, 두 오버레이가 겹쳐져 있고 위를 덮고 있는 오버레이에 이벤트 리스너가 등록되어 있지 않다면 아래에 덮힌 오버레이가 이벤트를 받습니다. 덮힌 오버레이가 없거나 이벤트 리스너가 등록되어 있지 않다면 지도가 탭된 것으로 간주됩니다.

results matching ""

    No results matching ""