사용자 인터페이스
사용자는 컨트롤, 제스처 등 다양한 방법으로 지도와 상호작용할 수 있습니다. 개발자는 사용자가 지도와 상호작용하는 방법을 제어하고, 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 메서드가 호출되며, 탭된 오버레이 객체가 파라미터로 전달됩니다.
오버레이의 터치 이벤트는 지도로 전파될 수 있습니다. 이벤트를 지도로 전파하려면 overlayTouchHandler
가 NO
를 반환하도록 구현합니다. 그렇게 하면 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 이벤트는 발생하지 않음
};
오버레이에서 이벤트가 전파되는 곳은 오직 지도뿐입니다. 즉, 이벤트가 발생한 오버레이의 아래에 다른 오버레이나 심벌이 겹쳐져 있더라도 이 오버레이나 심벌로는 이벤트가 전파되지 않습니다. 또한 이벤트 리스너가 등록되지 않은 오버레이는 탭 시 무시됩니다. 즉, 두 오버레이가 겹쳐져 있고 위를 덮고 있는 오버레이에 이벤트 리스너가 등록되어 있지 않다면 아래에 덮힌 오버레이가 이벤트를 받습니다. 덮힌 오버레이가 없거나 이벤트 리스너가 등록되어 있지 않다면 지도가 탭된 것으로 간주됩니다.