카메라 이동
카메라는 API 호출, 사용자의 제스처 등 다양한 방법으로 움직일 수 있습니다. API를 호출해 카메라를 움직이려면 CameraUpdate
객체와 moveCamera()
메서드를 사용합니다. CameraUpdate
의 다양한 속성을 사용해 카메라의 위치, 애니메이션, 콜백 등을 지정할 수 있습니다.
API 호출로 카메라 이동하기
카메라를 움직이려면 먼저 카메라를 어떻게 움직일지를 나타내는 CameraUpdate
객체를 생성해야 합니다. CameraUpdate
는 카메라를 이동할 위치, 방법 등을 정의하는 클래스입니다. CameraUpdate
객체는 오직 팩토리 메서드를 이용해서 생성할 수 있으며, CameraUpdate
클래스에 다양한 팩토리 메서드가 정의되어 있습니다. 다음은 몇 가지 팩토리 메서드에 대한 설명입니다.
toCameraPosition()
: 카메라의 위치를 지정한CameraPosition
으로 움직입니다.scrollTo()
: 카메라의 대상 지점을 지정한 좌표로 변경합니다.scrollBy()
: 카메라의 대상 지점을 지정한 픽셀만큼 상하좌우로 이동합니다.zoomTo()
: 카메라의 줌 레벨을 지정한 값으로 변경합니다.fitBounds()
: 영역이 온전히 보이는 좌표와 최대 줌 레벨로 카메라의 위치를 변경합니다.
생성한 객체를 파라미터로 삼아 NaverMap.moveCamera()
를 호출하면 카메라가 움직입니다.
다음은 대상 지점을 (37.5666102, 126.9783881)
로 변경하도록 지정하는 CameraUpdate
객체를 만들고 NaverMap.moveCamera()
를 호출해 카메라를 움직이는 예제입니다.
CameraUpdate cameraUpdate = CameraUpdate.scrollTo(new LatLng(37.5666102, 126.9783881));
naverMap.moveCamera(cameraUpdate);
Java
CameraUpdate cameraUpdate = CameraUpdate.scrollTo(new LatLng(37.5666102, 126.9783881));
naverMap.moveCamera(cameraUpdate);
Kotlin
val cameraUpdate = CameraUpdate.scrollTo(LatLng(37.5666102, 126.9783881))
naverMap.moveCamera(cameraUpdate)
애니메이션
생성한 CameraUpdate
객체를 이용해 moveCamera()
를 호출하기 전에 CameraUpdate.animate()
를 호출하면 카메라 이동에 애니메이션을 적용할 수 있습니다. 애니메이션이 지정되면 일정한 시간 동안 카메라가 목표 지점까지 서서히 움직입니다.
애니메이션 유형
CameraUpdate.animate()
를 사용하면 카메라 이동에 애니메이션을 적용할 수 있습니다. animate()
는 애니메이션의 유형을 의미하는 CameraAnimation
객체를 파라미터로 받습니다. CameraAnimation
열거형에 나열되어 있는 애니메이션 유형은 다음과 같습니다.
None
: 애니메이션 없이 이동합니다. 기본값입니다.Linear
: 일정한 속도로 이동합니다.Easing
: 부드럽게 가감속하며 이동합니다. 가까운 거리를 이동할 때 적합합니다.Fly
: 부드럽게 축소됐다가 확대되며 이동합니다. 먼 거리를 이동할 때 적합합니다.
다음은 카메라 이동에 Easing
애니메이션을 적용하는 예제입니다.
CameraUpdate cameraUpdate = CameraUpdate.scrollTo(new LatLng(37.5666102, 126.9783881))
.animate(CameraAnimation.Easing);
naverMap.moveCamera(cameraUpdate);
Java
CameraUpdate cameraUpdate = CameraUpdate.scrollTo(new LatLng(37.5666102, 126.9783881))
.animate(CameraAnimation.Easing);
naverMap.moveCamera(cameraUpdate);
Kotlin
val cameraUpdate = CameraUpdate.scrollTo(LatLng(37.5666102, 126.9783881))
.animate(CameraAnimation.Easing)
naverMap.moveCamera(cameraUpdate)
지속 시간
animate()
의 duration
파라미터를 지정하면 애니메이션의 지속 시간을 변경할 수 있습니다. 단, 애니메이션의 유형이 None
일 경우 시간은 무시됩니다. 또한 duration
이 0
일 경우 애니메이션의 유형을 지정하더라도 애니메이션 없이 이동합니다.
다음은 카메라 이동에 Fly
애니메이션을 적용하고 지속 시간을 1초로 지정하는 예제입니다.
CameraUpdate cameraUpdate = CameraUpdate.scrollTo(new LatLng(37.5666102, 126.9783881))
.animate(CameraAnimation.Fly, 1000);
naverMap.moveCamera(cameraUpdate);
Java
CameraUpdate cameraUpdate = CameraUpdate.scrollTo(new LatLng(37.5666102, 126.9783881))
.animate(CameraAnimation.Fly, 1000);
naverMap.moveCamera(cameraUpdate);
Kotlin
val cameraUpdate = CameraUpdate.scrollTo(LatLng(37.5666102, 126.9783881))
.animate(CameraAnimation.Fly, 1000)
naverMap.moveCamera(cameraUpdate)
지속 시간을 지정하지 않으면 지도의 기본 애니메이션 시간이 적용됩니다. 기본 애니메이션 시간은 NaverMap
의 defaultCameraAnimationDuration
속성을 사용해 변경할 수 있습니다.
다음은 지도의 기본 애니메이션 시간을 500밀리초로 변경하는 예제입니다.
naverMap.setDefaultCameraAnimationDuration(500);
Java
naverMap.setDefaultCameraAnimationDuration(500);
Kotlin
naverMap.defaultCameraAnimationDuration = 500
애니메이션 취소
진행 중인 카메라 이동 애니메이션은 다양한 이유로 취소되거나 취소할 수 있습니다. NaverMap.moveCamera()
를 호출해 새로운 카메라 이동을 시작하면 이전에 진행 중이던 카메라 이동이 자동으로 취소됩니다.
다음은 지속 시간이 2초인 카메라 애니메이션을 시작하고 1초 후 다른 카메라 이동을 시작해 기존 카메라 애니메이션을 취소하는 예제입니다.
LatLng coord1 = new LatLng(37.5666102, 126.9783881);
LatLng coord2 = new LatLng(37.57000, 126.97618);
// 2초간 카메라 애니메이션
naverMap.moveCamera(CameraUpdate.scrollTo(coord1).animate(CameraAnimation.Easing, 2000));
// 1초 후 다른 카메라 이동이 시작되며 기존 카메라 애니메이션이 취소됨
new Handler().postDelayed(() -> {
naverMap.moveCamera(CameraUpdate.scrollTo(coord2).animate(CameraAnimation.Easing))
}, 1000);
Java
LatLng coord1 = new LatLng(37.5666102, 126.9783881);
LatLng coord2 = new LatLng(37.57000, 126.97618);
// 2초간 카메라 애니메이션
naverMap.moveCamera(CameraUpdate.scrollTo(coord1).animate(CameraAnimation.Easing, 2000));
// 1초 후 다른 카메라 이동이 시작되며 기존 카메라 애니메이션이 취소됨
new Handler().postDelayed(() -> {
naverMap.moveCamera(CameraUpdate.scrollTo(coord2).animate(CameraAnimation.Easing))
}, 1000);
Kotlin
val coord1 = LatLng(37.5666102, 126.9783881)
val coord2 = LatLng(37.57000, 126.97618)
// 2초간 카메라 애니메이션
naverMap.moveCamera(CameraUpdate.scrollTo(coord1).animate(CameraAnimation.Easing, 2000))
// 1초 후 다른 카메라 이동이 시작되며 기존 카메라 애니메이션이 취소됨
Handler().postDelayed({
naverMap.moveCamera(CameraUpdate.scrollTo(coord2).animate(CameraAnimation.Easing))
}, 1000)
NaverMap.cancelTransitions()
를 사용해서 명시적으로 카메라 애니메이션을 취소할 수도 있습니다. 호출하면 현재 진행 중인 카메라 애니메이션이 취소되고 카메라가 현재 위치에 멈춥니다. 스톱 제스처가 활성화되어 있다면 사용자가 지도를 탭했을 때에도 동일한 결과가 일어납니다.
다음은 cancelTransitions()
를 호출해 카메라 애니메이션을 취소하는 예제입니다.
// 2초간 카메라 애니메이션
naverMap.moveCamera(CameraUpdate.scrollTo(coord1).animate(CameraAnimation.Easing, 2000));
// 1초 후 cancelTransitions()가 호출되며 기존 카메라 애니메이션이 취소됨
new Handler().postDelayed(() -> {
naverMap.cancelTransitions();
}, 1000);
Java
// 2초간 카메라 애니메이션
naverMap.moveCamera(CameraUpdate.scrollTo(coord1).animate(CameraAnimation.Easing, 2000));
// 1초 후 cancelTransitions()가 호출되며 기존 카메라 애니메이션이 취소됨
new Handler().postDelayed(() -> {
naverMap.cancelTransitions();
}, 1000);
Kotlin
// 2초간 카메라 애니메이션
naverMap.moveCamera(CameraUpdate.scrollTo(coord1).animate(CameraAnimation.Easing, 2000))
// 1초 후 cancelTransitions()가 호출되며 기존 카메라 애니메이션이 취소됨
Handler().postDelayed({
naverMap.cancelTransitions()
}, 1000)
콜백과 이벤트
CameraUpdate
의 콜백 속성을 사용하면 한 번의 카메라 이동에 대한 결과 콜백을 받을 수 있습니다. 또한 NaverMap
에 이벤트 리스너를 등록하면 지도에서 일어나는 모든 카메라 이동에 대한 이벤트를 받을 수 있습니다.
카메라 이동 콜백
finishCallback()
및 cancelCallback()
으로 콜백 객체를 지정하면 해당하는 CameraUpdate
에 대한 카메라 이동이 완료됐거나 실패했을 때 콜백을 받을 수 있습니다. 카메라 이동에 애니메이션이 지정되어 있고 그 애니메이션이 취소되었을 경우 cancelCallback()
에 지정된 콜백이 호출되고, 그 외의 경우에는 finishCallback()
에 지정된 콜백이 호출됩니다. 즉, 카메라 이동에 애니메이션이 지정되지 않았으면 카메라 이동은 항상 성공적으로 완료된 것으로 간주됩니다.
다음은 카메라 이동 완료 및 실패 시 토스트를 표시하는 콜백을 지정하는 예제입니다.
CameraUpdate cameraUpdate = CameraUpdate.scrollTo(new LatLng(37.5666102, 126.9783881))
.animate(CameraAnimation.Easing, 2000)
.finishCallback(() -> {
Toast.makeText(context, "카메라 이동 완료", Toast.LENGTH_SHORT).show();
})
.cancelCallback(() -> {
Toast.makeText(context, "카메라 이동 취소", Toast.LENGTH_SHORT).show();
});
naverMap.moveCamera(cameraUpdate);
Java
CameraUpdate cameraUpdate = CameraUpdate.scrollTo(new LatLng(37.5666102, 126.9783881))
.animate(CameraAnimation.Easing, 2000)
.finishCallback(() -> {
Toast.makeText(context, "카메라 이동 완료", Toast.LENGTH_SHORT).show();
})
.cancelCallback(() -> {
Toast.makeText(context, "카메라 이동 취소", Toast.LENGTH_SHORT).show();
});
naverMap.moveCamera(cameraUpdate);
Kotlin
val cameraUpdate = CameraUpdate.scrollTo(LatLng(37.5666102, 126.9783881))
.animate(CameraAnimation.Easing, 2000)
.finishCallback {
Toast.makeText(context, "카메라 이동 완료", Toast.LENGTH_SHORT).show()
}
.cancelCallback {
Toast.makeText(context, "카메라 이동 취소", Toast.LENGTH_SHORT).show()
}
naverMap.moveCamera(cameraUpdate)
카메라 변경 이벤트
어떤 이유에 의해서건 카메라가 움직이면 카메라 변경 이벤트가 발생합니다. NaverMap.addOnCameraChangeListener()
메서드로 OnCameraChangeListener
를 등록하면 카메라 변경 이벤트를 받을 수 있습니다. 카메라의 위치가 변경되면 onCameraChange()
콜백 메서드가 호출됩니다.
onCameraChange()
에는 reason
과 animated
파라미터가 전달됩니다. reason
은 이벤트를 발생시킨 카메라 이동의 원인입니다. CameraUpdate.reason()
을 호출해 카메라 이동의 원인을 지정할 수 있으며, 이벤트 리스너 내에서 이 값을 이용해 어떤 원인에 의해 발생한 이벤트인지를 판단할 수 있습니다. 제스처, 컨트롤 등 네이버 지도 SDK의 내장 기능에 의해 카메라가 이동한 경우 미리 정의된 음숫값을 가지며, 개발자가 임의의 양숫값을 지정할 수도 있습니다. 미리 정의되어 있는 원인은 다음과 같습니다.
REASON_DEVELOPER
: 개발자가 API를 호출해 카메라가 움직였음을 나타냅니다. 기본값입니다.REASON_GESTURE
: 사용자의 제스처로 인해 카메라가 움직였음을 나타냅니다.REASON_CONTROL
: 사용자의 버튼 선택으로 인해 카메라가 움직였음을 나타냅니다.REASON_LOCATION
: 위치 트래킹 기능으로 인해 카메라가 움직였음을 나타냅니다.
animated
는 이벤트를 발생시킨 카메라 이동에 애니메이션이 지정되어 있는지 여부를 나타냅니다.
다음은 카메라 변경시 원인을 로깅하는 이벤트 리스너를 등록하고, 원인을 지정해 카메라를 이동시키는 예제입니다.
naverMap.addOnCameraChangeListener((reason, animated) -> {
Log.i("NaverMap", "카메라 변경 - reson: " + reason + ", animated: " + animated);
});
CameraUpdate cameraUpdate = CameraUpdate.scrollTo(new LatLng(37.5666102, 126.9783881))
.animate(CameraAnimation.Easing, 2000)
.reason(1000);
naverMap.moveCamera(cameraUpdate);
Java
naverMap.addOnCameraChangeListener((reason, animated) -> {
Log.i("NaverMap", "카메라 변경 - reson: " + reason + ", animated: " + animated);
});
CameraUpdate cameraUpdate = CameraUpdate.scrollTo(new LatLng(37.5666102, 126.9783881))
.animate(CameraAnimation.Easing, 2000)
.reason(1000);
naverMap.moveCamera(cameraUpdate);
Kotlin
naverMap.addOnCameraChangeListener { reason, animated ->
Log.i("NaverMap", "카메라 변경 - reson: $reason, animated: $animated")
}
val cameraUpdate = CameraUpdate.scrollTo(LatLng(37.5666102, 126.9783881))
.animate(CameraAnimation.Easing, 2000)
.reason(1000)
naverMap.moveCamera(cameraUpdate)
카메라 대기 이벤트
카메라의 움직임이 끝나 대기 상태가 되면 카메라 대기 이벤트가 발생합니다. NaverMap.addOnCameraIdleListener()
메서드로 OnCameraIdleListener
를 등록하면 카메라 대기 이벤트를 받을 수 있습니다. 카메라가 대기 상태가 되면 onCameraIdle()
콜백 메서드가 호출됩니다.
카메라는 다음과 같은 시점에 대기 상태가 된 것으로 간주되어 이벤트가 발생합니다.
- 카메라가 애니메이션 없이 움직일 때. 단, 사용자가 제스처로 지도를 움직이는 경우 제스처가 완전히 끝날 때까지(
ACTION_UP
이 발생할 때까지)는 연속적인 이동으로 간주되어 이벤트가 발생하지 않습니다. - 카메라 애니메이션이 완료될 때. 단, 카메라 애니메이션이 진행 중일 때 새로운 애니메이션이 발생하거나, 기존 카메라 이동의
finishCallback()
또는cancelCallback()
으로 지정된 콜백 내에서 카메라 이동이 일어날 경우 연속적인 이동으로 간주되어 이벤트가 발생하지 않습니다. NaverMap.cancelTransitions()
가 호출되어 카메라 애니메이션이 명시적으로 취소될 때.
다음은 카메라가 대기 상태가 되면 토스트를 표시하는 예제입니다.
naverMap.addOnCameraIdleListener(() -> {
Toast.makeText(context, "카메라 움직임 종료", Toast.LENGTH_SHORT).show();
});
Java
naverMap.addOnCameraIdleListener(() -> {
Toast.makeText(context, "카메라 움직임 종료", Toast.LENGTH_SHORT).show();
});
Kotlin
naverMap.addOnCameraIdleListener {
Toast.makeText(context, "카메라 움직임 종료", Toast.LENGTH_SHORT).show()
}
피봇
CameraUpdate.pivot()
메서드를 사용해 피봇 지점을 지정할 수 있습니다. 피봇 지점은 화면의 왼쪽 위를 (0, 0)
, 오른쪽 아래를 (1, 1)
로 삼는 비율값으로, 카메라를 움직일 때 기준점이 되는 화면상 지점을 의미합니다. 피봇 지점이 지정되면 이동, 줌 레벨 변경, 회전이 화면 중심이 아닌 해당 지점을 기준으로 이루어집니다.
예를 들어 피봇 지점을 (0.5, 0.8)
로 지정하고 카메라를 이동하면, 카메라 이동이 완료된 후 (0.5, 0.8)
지점의 좌표가 카메라 이동의 대상 지점과 일치하게 됩니다. 동일한 피봇 지점을 지정하고 지도를 확대하면 지도의 중심이 아닌 (0.5, 0.8)
지점을 기준으로 지도가 확대됩니다. 따라서 피봇 지점을 지정하면 카메라 이동이 완료된 후 카메라의 위치가 카메라 이동에서 지정했던 위치와 다를 수 있습니다.
피봇은 카메라가 위치해야 하는 화면상 지점을 지정한다는 측면에서는 콘텐츠 패딩과 동일한 역할을 합니다. 그러나 NaverMap
의 속성인 콘텐츠 패딩과 달리 피봇은 CameraUpdate
의 속성이므로 하나의 카메라 변경에만 적용되며, 지도 객체에 영구적으로 영향을 미치지 않습니다.
다음은 피봇 지점을 (0.5, 0.8)
로 지정하고 카메라를 이동시키는 예제입니다.
CameraUpdate cameraUpdate = CameraUpdate.scrollTo(new LatLng(37.5666102, 126.9783881))
.pivot(new PointF(0.5f, 0.8f));
naverMap.moveCamera(cameraUpdate);
Java
CameraUpdate cameraUpdate = CameraUpdate.scrollTo(new LatLng(37.5666102, 126.9783881))
.pivot(new PointF(0.5f, 0.8f));
naverMap.moveCamera(cameraUpdate);
Kotlin
val cameraUpdate = CameraUpdate.scrollTo(LatLng(37.5666102, 126.9783881))
.pivot(PointF(0.5f, 0.8f))
naverMap.moveCamera(cameraUpdate)
이동 제한
NaverMap
의 속성을 지정하면 카메라가 이동할 수 있는 영역과 최소 및 최대 줌 레벨을 제한할 수 있습니다.
최소 및 최대 줌 레벨
minZoom
및 maxZoom
속성을 지정하면 카메라의 최소 및 최대 줌 레벨을 제한할 수 있습니다.
다음은 카메라의 줌 레벨을 5~18 범위로 제한하는 예제입니다.
naverMap.setMinZoom(5.0);
naverMap.setMaxZoom(18.0);
Java
naverMap.setMinZoom(5.0);
naverMap.setMaxZoom(18.0);
Kotlin
naverMap.minZoom = 5.0
naverMap.maxZoom = 18.0
카메라 영역 제한
extent
속성을 지정하면 카메라의 대상 지점을 영역 내로 제한할 수 있습니다. 카메라가 제한 영역을 벗어나도록 API를 호출하더라도 대상 지점이 영역 내로 조정됩니다.
다음은 카메라의 대상 지점을 한반도 인근으로 제한하는 예제입니다.
naverMap.setExtent(new LatLngBounds(new LatLng(31.43, 122.37), new LatLng(44.35, 132)));
Java
naverMap.setExtent(new LatLngBounds(new LatLng(31.43, 122.37), new LatLng(44.35, 132)));
Kotlin
naverMap.extent = LatLngBounds(LatLng(31.43, 122.37), LatLng(44.35, 132.0))
카메라 영역을 제한할 때 최소 줌 레벨도 함께 제한하는 것이 좋습니다. 그렇지 않으면 지도가 축소되었을 때 제한 영역이 너무 작게 나타날 수 있습니다.