카메라와 뷰

지도의 카메라를 변경하여 사용자가 바라보는 뷰 시점의 지도를 자유롭게 움직일 수 있는 기능을 설명합니다. 카메라 이동, 줌 레벨 변경, 기울기 조정, 화면 회전 등이 가능합니다.

카메라의 위치

CameraPosition은 카메라의 위치를 나타내는 클래스입니다. 카메라의 위치는 카메라가 놓여 있는 대상 지점의 좌표와 줌 레벨, 기울기 각도, 베어링 각도로 구성됩니다.

대상 지점

현재 지도가 표출되고 있는 지점을 의미합니다. target 속성으로 대상 지점을 설정할 수 있습니다.

줌 레벨

현재 지도의 축척을 의미합니다. zoom 속성으로 줌 레벨을 설정할 수 있습니다. 줌 레벨이 작을수록 화면에 보이는 지역이 넓어집니다. 반대로 줌 레벨이 클수록 지도에 상세한 정보가 표출됩니다.

기울기 각도

카메라가 위에서 지도를 바라보는 수직적 각도를 의미합니다. tilt 속성으로 기울기 각도를 설정할 수 있습니다. 기울기 각도가 0일 때 카메라는 지도를 수직으로 내려다보며, 값이 증가할수록 카메라의 시점이 수평에 가까워집니다. 기울기 각도가 클수록 더 먼 지점을 볼 수 있고, 지도에 원근감 효과가 크게 적용됩니다.

베어링 각도

카메라가 지도를 바라보는 수평적 각도, 즉 방향을 의미합니다. bearing 속성으로 베어링 각도를 설정할 수 있습니다. 베어링 각도가 0일 때 지도는 정북 방향을 바라보며, 값이 증가할 수록 시계 방향으로 회전합니다. 값이 360이 되면 지도는 다시 정북 방향을 바라보게 됩니다.

CameraPosition 객체

CameraPosition의 모든 속성은 final이므로 생성자로만 설정할 수 있으며, 한 번 생성된 객체의 속성은 변경할 수 없습니다.

// CameraPosition 객체 생성
val cameraPosition = CameraPosition(
        LatLng(36.99473, 127.81832), // 대상 지점
        16.0, // 줌 레벨
        20.0, // 기울기 각도
        180.0 // 베어링 각도
)

// CameraPosition 정보 토스트 메시지로 표출
Toast.makeText(context,
        "대상 지점: (${cameraPosition.target.latitude}, " +
        "${cameraPosition.target.longitude}), " +
        "줌 레벨: ${cameraPosition.zoom}, " +
        "기울임 각도: ${cameraPosition.tilt}, " +
        "베어링 각도: ${cameraPosition.bearing}",
        Toast.LENGTH_SHORT).show()

CameraPosition 객체를 생성할 때 기울기 각도와 베어링 각도는 생략할 수 있습니다. 생략할 경우 각 값은 0으로 설정됩니다.

// 대상 지점, 줌 레벨을 지정하여 CameraPosition 객체 생성
// 기울기 각도와 베어링 각도는 0으로 설정된다.
val cameraPosition = CameraPosition(LatLng(36.99473, 127.81832), 16.0)

뷰와 카메라

카메라는 기본적으로 지도 뷰의 중심에 위치합니다. 그러나 패딩이 설정되면 카메라의 위치에 영향을 미칩니다.

카메라의 현재 위치

InaviMap 객체의 cameraPosition 속성으로 카메라의 현재 위치를 가져오거나 새로 설정할 수 있습니다.

// 카메라의 위치 설정
inaviMap.cameraPosition = cameraPosition

// 카메라의 위치 가져오기
val myCameraPosition = inaviMap.cameraPosition

패딩

InaviMap 객체의 padding 속성으로 지도의 패딩을 가져오거나 새로 설정할 수 있습니다.

앱에서 사용하는 UI 요소에 가려진 지도의 영역을 패딩으로 설정할 수 있습니다. 패딩을 설정하면 카메라는 패딩을 제외한 영역의 중심에 위치하게 됩니다. 패딩을 변경하면 지도의 중심이 변경되므로 카메라의 위치도 변경됩니다.

// 하단 패딩을 200px로 설정
inaviMap.setPadding(0, 0, 0, 200)

투영

화면은 왼쪽 위를 기준점으로 삼는 픽셀 단위 좌표계를 사용하고, 지도는 지리적 위경도 좌표계를 사용합니다. Projection 클래스를 이용하여 화면 좌표와 지도 좌표를 서로 변환할 수 있습니다. Projection 객체는 InaviMap#getProjection() 함수 호출을 통해서만 얻을 수 있습니다.

val projection = inaviMap.projection // Projection 인스턴스 가져오기

화면 좌표와 지도 좌표 간 변환

Projection 클래스에서 제공하는 함수로 화면상의 좌표와 지도상의 좌표를 상호 변환할 수 있습니다.

// 화면상 (100, 100) 지점의 좌표를 지도상의 좌표로 변환
val mapCoords = projection.getLatLngFromPoint(PointF(100f, 100f))

// 지도상 (37.40219, 127.11077) 지점의 좌표를 화면상의 좌표로 변환
val screenCoords = projection.getPointFromLatLng(LatLng(37.40219, 127.11077))

축척

지도는 3차원인 지구의 표면을 2차원으로 표현하기 때문에 왜곡이 발생합니다. 아이나비 지도 SDK는 웹 메르카토르 투영법을 사용해 지구 구체를 평면으로 표현하므로 줌 레벨 뿐만 아니라 위도에 따라서도 축척이 달라집니다.

getMetersPerPixel() 또는 getMetersPerDp() 함수를 통해 현재 카메라가 위치한 지점의 축척을 각각 미터/픽셀, 미터/DP 단위로 얻을 수 있습니다.

// 현재 카메라의 축척을 미터/픽셀 단위로 가져오기
val metersPerPixel = projection.metersPerPixel

// 현재 카메라의 축척을 미터/DP 단위 단위로 가져오기
val metersPerDp = projection.metersPerDp

getMetersPerPixel(latitude, zoom) 또는 getMetersPerDp(latitude, zoom) 함수를 통해 현재 카메라의 위치와 무관하게 특정한 위도와 줌 레벨에서의 축척을 구할 수 있습니다.

// 적도, 줌 레벨 10
val metersPerPixel1 = projection.getMetersPerPixel(0.0, 10.0)

// 위도 35도, 줌 레벨 10: 적도보다 축척이 커짐
val metersPerPixel2 = projection.getMetersPerPixel(35.0, 10.0)

// 위도 35도, 줌 레벨 15: 줌 레벨 10보다 축척이 커짐
val metersPerPixel3 = projection.getMetersPerPixel(35.0, 15.0)

// 적도, 줌 레벨 10, 미터/DP 단위
val metersPerDp1 = projection.getMetersPerDp(0.0, 10.0)

카메라 이동

CameraUpdate는 카메라를 이동할 위치, 방법 등 카메라를 어떻게 움직일지를 정의한 클래스입니다. CameraUpdate 객체는 CameraUpdate 클래스에서 제공하는 팩토리 메서드를 이용하여 생성할 수 있습니다.

CameraUpdate 클래스에서 제공하는 대표적인 팩토리 메서드는 다음과 같습니다.

  • newCameraPosition(): 카메라의 위치를 CameraPosition 객체의 좌표로 변경합니다.

  • targetTo(): 카메라의 대상 지점을 지정한 좌표로 변경합니다.

  • zoomTo(): 카메라의 줌 레벨을 지정한 값으로 변경합니다.

  • zoomBy(): 카메라의 줌 레벨을 지정한 값만큼 변경합니다.

  • fitBounds(): 영역이 온전히 보이는 좌표와 최대 줌 레벨로 카메라의 위치를 변경합니다.

CameraUpdate 객체를 InaviMap#moveCamera() 함수의 파라미터로 설정하여 호출하면 카메라가 이동됩니다.

// 대상 지점을 (36.99473, 127.81832)로 설정하여 카메라 이동
val cameraUpdate = CameraUpdate.targetTo(LatLng(36.99473, 127.81832))
inaviMap.moveCamera(cameraUpdate)

애니메이션

animationType 속성으로 카메라 이동 시 적용할 애니메이션의 유형을 가져오거나 새로 설정할 수 있습니다. 카메라 애니메이션의 종류는 CameraAnimationType 열거형에 정의되어 있습니다. 카메라 이동에 적용할 수 있는 애니메이션 유형은 다음과 같습니다.

  • None: 애니메이션 없이 이동합니다. (기본값)

  • Linear: 일정한 속도로 이동합니다.

  • Easing: 부드럽게 가속, 감속하면서 이동합니다.

  • Fly: 부드럽게 축소되었다가 확대되면서 이동합니다.

durationMs 속성으로 애니메이션이 완료되기까지의 소요시간을 가져오거나 새로 설정할 수 있습니다. animationType 속성의 값이 None일 때에는 효과가 무시됩니다.

// 카메라 이동에 Fly 애니메이션 적용
cameraUpdate.animationType = CameraAnimationType.Fly

// 카메라 애니메이션 소요시간을 5초로 설정
cameraUpdate.durationMs = 5000

애니메이션 취소

진행 중인 카메라 이동 애니메이션은 다양한 이유로 취소되거나 취소할 수 있습니다. InaviMap#moveCamera() 함수를 호출하여 새로운 카메라 이동을 시작하면 이전에 진행 중이던 카메라 이동은 자동으로 취소됩니다.

val POSITION1 = LatLng(36.99473, 127.81832)
val POSITION2 = LatLng(37.40219, 127.11077)

// 5초간 카메라 애니메이션
inaviMap.moveCamera(CameraUpdate.targetTo(POSITION1)
    .setAnimationType(CameraAnimationType.Easing, 5000))

// 3초 후 새로운 카메라 이동이 시작되면서 기존 카메라 애니메이션이 취소됨
Handler().postDelayed({
    inaviMap.moveCamera(CameraUpdate.targetTo(POSITION2)
        .setAnimationType(CameraAnimationType.Fly, 3000))
}, 3000)

InaviMap#cancelTransitions() 함수를 호출하여 명시적으로 카메라 애니메이션을 취소할 수도 있습니다. 이 함수를 호출하면 현재 진행 중인 카메라 애니메이션이 취소되고 카메라가 현재 위치에 멈춥니다. 애니메이션 도중 사용자가 지도를 탭했을 경우에도 동일한 결과가 일어납니다.

// 5초간 카메라 애니메이션
inaviMap.moveCamera(CameraUpdate.targetTo(LatLng(36.99473, 127.81832))
    .setAnimationType(CameraAnimationType.Easing, 5000))

// 3초 후 cancelTransitions()가 호출되어 기존 카메라 애니메이션이 취소됨
Handler().postDelayed({
    inaviMap.cancelTransitions()
}, 3000)

콜백과 이벤트

CameraUpdate 객체에 콜백을 설정하는 함수를 사용하면 특정 카메라 이동의 결과에 대한 이벤트를 감지할 수 있습니다. 또한 InaviMap 객체에 이벤트 리스너를 추가하면 지도에서 일어나는 모든 카메라 이동에 대한 이벤트를 감지할 수 있습니다.

카메라 이동 콜백

CameraUpdate 객체에서 setFinishCallback()setCancelCallback() 함수를 호출하여 콜백 객체를 설정하면 해당 CameraUpdate의 카메라 이동이 완료되었거나 취소되었을 때에 대한 이벤트를 감지할 수 있습니다. animationType 속성의 값이 None이면 카메라 이동은 취소 없이 항상 완료된 것으로 간주됩니다.

val cameraUpdate = CameraUpdate.targetTo(LatLng(36.99473, 127.81832))
    .setAnimationType(CameraAnimationType.Fly, 5000)
    .durationMs = 5000
    .setFinishCallback {
        Toast.makeText(context, "카메라 이동 완료", Toast.LENGTH_SHORT).show()
    }
    .setCancelCallback {
        Toast.makeText(context, "카메라 이동 취소", Toast.LENGTH_SHORT).show()
    }

inaviMap.moveCamera(cameraUpdate)

카메라 변경 이벤트

InaviMap#addOnCameraChangeListener() 함수를 호출하여 카메라 변경에 대한 이벤트를 감지할 수 있습니다.

onCameraChange() 콜백 함수에는 reason 파라미터가 전달되며, 이는 이벤트를 발생시킨 카메라 이동의 원인을 의미합니다. CameraUpdate 객체의 reason 속성으로 카메라 이동의 원인을 가져오거나 새로 설정할 수 있습니다. 콜백 함수에서 이 값을 이용하여 어떤 원인에 의해 발생한 이벤트인지를 판단할 수 있습니다.

제스처, 컨트롤 등 아이나비 지도 SDK의 내장 기능에 의해 카메라가 이동한 경우 미리 정의된 음숫값을 가지며, 개발자가 임의의 양숫값을 설정할 수도 있습니다. 카메라 이동의 원인은 CameraUpdate 클래스에 상수로 정의되어 있으며, 상세 내용은 다음과 같습니다.

// 카메라 변경 발생 시 이벤트 처리
inaviMap.addOnCameraChangeListener { reason -> 
    Toast.makeText(context, "카메라 변경 / reason : $reason", 
        Toast.LENGTH_SHORT).show()
}

// reason을 임의의 값으로 설정하여 CameraUpdate 객체 생성
val cameraUpdate = CameraUpdate.targetTo(LatLng(36.99473, 127.81832))
    .setAnimationType(CameraAnimationType.Fly, 5000)
    .setReason(1000)

inaviMap.moveCamera(cameraUpdate)

Last updated