카메라 이동

카메라는 API 호출, 사용자의 제스처 등 다양한 방법으로 움직일 수 있습니다. API를 호출해 카메라를 움직이려면 NMFCameraUpdate 객체와 -moveCamera: 메서드를 사용합니다. NMFCameraUpdate의 다양한 속성을 사용해 카메라의 위치, 애니메이션, 콜백 등을 지정할 수 있습니다.

API 호출로 카메라 이동하기

카메라를 움직이려면 먼저 카메라를 어떻게 움직일지를 나타내는 NMFCameraUpdate 객체를 생성해야 합니다. NMFCameraUpdate는 카메라를 이동할 위치, 방법 등을 정의하는 클래스입니다. NMFCameraUpdate 객체는 오직 팩토리 메서드를 이용해서 생성할 수 있으며, NMFCameraUpdate 클래스에 다양한 팩토리 메서드가 정의되어 있습니다. 다음은 몇 가지 팩토리 메서드에 대한 설명입니다.

  • +cameraUpdateWithPosition:cameraUpdateWithPosition:): 카메라의 위치를 지정한 CameraPosition으로 움직입니다.
  • +cameraUpdateWithScrollTo:cameraUpdateWithScrollTo:): 카메라의 대상 지점을 지정한 좌표로 변경합니다.
  • +cameraUpdateWithScrollBy:cameraUpdateWithScrollBy:): 카메라의 대상 지점을 지정한 포인트만큼 상하좌우로 이동합니다.
  • +cameraUpdateWithZoomTo:cameraUpdateWithZoomTo:): 카메라의 줌 레벨을 지정한 값으로 변경합니다.
  • +cameraUpdateWithFitBounds:cameraUpdateWithFitBounds:): 영역이 온전히 보이는 좌표와 최대 줌 레벨로 카메라의 위치를 변경합니다.

생성한 객체를 파라미터로 삼아 NMFMapView-moveCamera:를 호출하면 카메라가 움직입니다.

다음은 대상 지점을 (37.5666102, 126.9783881)로 변경하도록 지정하는 NMFCameraUpdate 객체를 만들고 -moveCamera:를 호출해 카메라를 움직이는 예제입니다.

let cameraUpdate = NMFCameraUpdate(scrollTo: NMGLatLng(lat: 37.5666102, lng: 126.9783881))
mapView.moveCamera(cameraUpdate)

Swift

let cameraUpdate = NMFCameraUpdate(scrollTo: NMGLatLng(lat: 37.5666102, lng: 126.9783881))
mapView.moveCamera(cameraUpdate)

Objective-C

NMFCameraUpdate *cameraUpdate = [NMFCameraUpdate cameraUpdateWithScrollTo:NMGLatLngMake(37.5666102, 126.9783881)];
[self.mapView moveCamera:cameraUpdate];

애니메이션

생성한 NMFCameraUpdate 객체를 이용해 -moveCamera:를 호출하기 전에 NMFCameraUpdate.animation 속성을 지정하면 카메라 이동에 애니메이션을 적용할 수 있습니다. 애니메이션이 지정되면 일정한 시간 동안 카메라가 목표 지점까지 서서히 움직입니다.

애니메이션 유형

NMFCameraUpdate.animation을 사용하면 카메라 이동에 애니메이션을 적용할 수 있습니다. animation은 애니메이션의 유형을 의미하는 NMFCameraUpdateAnimation 객체를 파라미터로 받습니다. NMFCameraUpdateAnimation 열거형에 나열되어 있는 애니메이션 유형은 다음과 같습니다.

  • None: 애니메이션 없이 이동합니다. 기본값입니다.
  • Linear: 일정한 속도로 이동합니다.
  • EaseIn: 부드럽게 가속하며 이동합니다. 가까운 거리를 이동할 때 적합합니다.
  • EaseOut: 부드럽게 감속하며 이동합니다. 가까운 거리를 이동할 때 적합합니다.
  • Fly: 부드럽게 축소됐다가 확대되며 이동합니다. 먼 거리를 이동할 때 적합합니다.

다음은 카메라 이동에 EaseIn 애니메이션을 적용하는 예제입니다.

let cameraUpdate = NMFCameraUpdate(scrollTo: NMGLatLng(lat: 37.5666102, lng: 126.9783881))
cameraUpdate.animation = .easeIn
mapView.moveCamera(cameraUpdate)

Swift

let cameraUpdate = NMFCameraUpdate(scrollTo: NMGLatLng(lat: 37.5666102, lng: 126.9783881))
cameraUpdate.animation = .easeIn
mapView.moveCamera(cameraUpdate)

Objective-C

NMFCameraUpdate *cameraUpdate = [NMFCameraUpdate cameraUpdateWithScrollTo:NMGLatLngMake(37.5666102, 126.9783881)];
cameraUpdate.animation = NMFCameraUpdateAnimationEaseIn
[self.mapView moveCamera:cameraUpdate];

지속 시간

NMFCameraUpdateanimationDuration 파라미터를 지정하면 애니메이션의 지속 시간을 변경할 수 있습니다. 단, 애니메이션의 유형이 NMFCameraUpdateAnimationNone일 경우 시간은 무시됩니다. 또한 animationDuration0일 경우 애니메이션의 유형을 지정하더라도 애니메이션 없이 이동합니다.

다음은 카메라 이동에 Fly 애니메이션을 적용하고 지속 시간을 1초로 지정하는 예제입니다.

let cameraUpdate = NMFCameraUpdate(scrollTo: NMGLatLng(lat: 37.5666102, lng: 126.9783881))
cameraUpdate.animation = .fly
cameraUpdate.animationDuration = 1
mapView.moveCamera(cameraUpdate)

Swift

let cameraUpdate = NMFCameraUpdate(scrollTo: NMGLatLng(lat: 37.5666102, lng: 126.9783881))
cameraUpdate.animation = .fly
cameraUpdate.animationDuration = 1
mapView.moveCamera(cameraUpdate)

Objective-C

NMFCameraUpdate *cameraUpdate = [NMFCameraUpdate cameraUpdateWithScrollTo:NMGLatLngMake(37.5666102, 126.9783881)];
cameraUpdate.animation = NMFCameraUpdateAnimationFly;
cameraUpdate.animationDuration = 1;
[self.mapView moveCamera:cameraUpdate];

지속 시간을 지정하지 않으면 지도의 기본 애니메이션 시간이 적용됩니다. 기본 애니메이션 시간은 NMFMapViewanimationDuration 속성을 사용해 변경할 수 있습니다.

다음은 지도의 기본 애니메이션 시간을 500밀리초로 변경하는 예제입니다.

mapView.animationDuration = 0.5

Swift

mapView.animationDuration = 0.5

Objective-C

mapView.animationDuration = 0.5f;

애니메이션 취소

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

다음은 지속 시간이 2초인 카메라 애니메이션을 시작하고 1초 후 다른 카메라 이동을 시작해 기존 카메라 애니메이션을 취소하는 예제입니다.

let coord1 = NMGLatLng(lat: 37.5666102, lng: 126.9783881);
let coord2 = NMGLatLng(lat: 37.57000, lng: 126.97618);

// 2초간 카메라 애니메이션
let cameraUpdate = NMFCameraUpdate(scrollTo: coord1)
cameraUpdate.animation = .easeIn
cameraUpdate.animationDuration = 2
mapView.moveCamera(cameraUpdate)

// 1초 후 다른 카메라 이동이 시작되며 기존 카메라 애니메이션이 취소됨
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
    let cameraUpdate = NMFCameraUpdate(scrollTo: coord2)
    cameraUpdate.animation = .easeIn
    mapView.moveCamera(cameraUpdate)
}

Swift

let coord1 = NMGLatLng(lat: 37.5666102, lng: 126.9783881);
let coord2 = NMGLatLng(lat: 37.57000, lng: 126.97618);

// 2초간 카메라 애니메이션
let cameraUpdate = NMFCameraUpdate(scrollTo: coord1)
cameraUpdate.animation = .easeIn
cameraUpdate.animationDuration = 2
mapView.moveCamera(cameraUpdate)

// 1초 후 다른 카메라 이동이 시작되며 기존 카메라 애니메이션이 취소됨
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
    let cameraUpdate = NMFCameraUpdate(scrollTo: coord2)
    cameraUpdate.animation = .easeIn
    mapView.moveCamera(cameraUpdate)
}

Objective-C

NMGLatLng *coord1 = NMGLatLngMake(37.5666102, 126.9783881);
NMGLatLng *coord2 = NMGLatLngMake(37.57000, 126.97618);

// 2초간 카메라 애니메이션
NMFCameraUpdate *cameraUpdate = [NMFCameraUpdate cameraUpdateWithScrollTo:coord1];
cameraUpdate.animation = NMFCameraUpdateAnimationEaseIn;
cameraUpdate.animationDuration = 2;
[self.mapView moveCamera:cameraUpdate];

// 1초 후 다른 카메라 이동이 시작되며 기존 카메라 애니메이션이 취소됨
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    NMFCameraUpdate *cameraUpdate = [NMFCameraUpdate cameraUpdateWithScrollTo:coord2];
    cameraUpdate.animation = NMFCameraUpdateAnimationEaseIn;
    [self.mapView moveCamera:cameraUpdate];
});

NMFMapView-cancelTransitions를 사용해서 명시적으로 카메라 애니메이션을 취소할 수도 있습니다. 호출하면 현재 진행 중인 카메라 애니메이션이 취소되고 카메라가 현재 위치에 멈춥니다. 스톱 제스처가 활성화되어 있다면 사용자가 지도를 탭했을 때에도 동일한 결과가 일어납니다.

다음은 -cancelTransitions를 호출해 카메라 애니메이션을 취소하는 예제입니다.

// 2초간 카메라 애니메이션
let cameraUpdate = NMFCameraUpdate(scrollTo: coord1)
cameraUpdate.animation = .easeIn
cameraUpdate.animationDuration = 2
mapView.moveCamera(cameraUpdate)

// 1초 후 cancelTransitions()가 호출되며 기존 카메라 애니메이션이 취소됨
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
    mapView.cancelTransitions()
}

Swift

// 2초간 카메라 애니메이션
let cameraUpdate = NMFCameraUpdate(scrollTo: coord1)
cameraUpdate.animation = .easeIn
cameraUpdate.animationDuration = 2
mapView.moveCamera(cameraUpdate)

// 1초 후 cancelTransitions()가 호출되며 기존 카메라 애니메이션이 취소됨
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
    mapView.cancelTransitions()
}

Objective-C

// 2초간 카메라 애니메이션
NMFCameraUpdate *cameraUpdate = [NMFCameraUpdate cameraUpdateWithScrollTo:coord1];
cameraUpdate.animation = NMFCameraUpdateAnimationEaseIn;
cameraUpdate.animationDuration = 2;
[self.mapView moveCamera:cameraUpdate];

// 1초 후 cancelTransitions()가 호출되며 기존 카메라 애니메이션이 취소됨
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    [self.mapView cancelTransitions];
});

콜백과 이벤트

-moveCamera:대신 -moveCamera:completion:의 completion block을 사용하면 한 번의 카메라 이동에 대한 결과 콜백을 받을 수 있습니다. 또한 NMFMapView에 델리게이트를 등록하면 지도에서 일어나는 모든 카메라 이동에 대한 이벤트를 받을 수 있습니다.

카메라 이동 콜백

-moveCamera:completion:으로 콜백 블록을 구현하면 해당하는 NMFCameraUpdate에 대한 카메라 이동이 완료됐거나 실패했을 때 콜백을 받을 수 있습니다. 카메라 이동에 애니메이션이 지정되어 있고 그 애니메이션이 취소되었을 경우 completion block의 isCancelled 파라미터가 YES, 그 외의 경우에는 NO로 지정됩니다. 즉, 카메라 이동에 애니메이션이 지정되지 않았으면 카메라 이동은 항상 성공적으로 완료된 것으로 간주됩니다.

다음은 카메라 이동 완료 및 실패 시 토스트를 표시하는 콜백을 지정하는 예제입니다.

let cameraUpdate = NMFCameraUpdate(scrollTo: NMGLatLng(lat: 37.5666102, lng: 126.9783881))
cameraUpdate.animation = .easeIn
cameraUpdate.animationDuration = 2
mapView.moveCamera(cameraUpdate) { (isCancelled) in
    if isCancelled {
        print("카메라 이동 취소")
    } else {
        print("카메라 이동 완료")
    }
}

Swift

let cameraUpdate = NMFCameraUpdate(scrollTo: NMGLatLng(lat: 37.5666102, lng: 126.9783881))
cameraUpdate.animation = .easeIn
cameraUpdate.animationDuration = 2
mapView.moveCamera(cameraUpdate) { (isCancelled) in
    if isCancelled {
        print("카메라 이동 취소")
    } else {
        print("카메라 이동 완료")
    }
}

Objective-C

NMFCameraUpdate *cameraUpdate = [NMFCameraUpdate cameraUpdateWithScrollTo:NMGLatLngMake(37.5666102, 126.9783881)];
cameraUpdate.animation = NMFCameraUpdateAnimationEaseIn;
cameraUpdate.animationDuration = 2;
[self.mapView moveCamera:cameraUpdate completion:^(bool isCancelled) {
    if (isCancelled) {
        NSLog(@"카메라 이동 취소");
    } else {
        NSLog(@"카메라 이동 완료");
    }
}];

카메라 변경 이벤트

어떤 이유에 의해서건 카메라가 움직이면 카메라 변경 이벤트가 발생합니다. NMFMapView를 사용 중인 뷰 컨트롤러에 NMFMapViewCameraDelegate 프로토콜을 선언하고, -mapView:addCameraDelegate로 등록하면 카메라 변경 이벤트를 받을 수 있습니다. 카메라의 위치가 변경되면 -mapView:cameraIsChangingByReason: 콜백 메서드가 호출됩니다.

카메라 이동이 시작되기 전 호출되는 -mapView:cameraWillChangeByReason:과 이동이 완료된 후 호출되는 -mapView:cameraDidChangeByReason:에는 reasonanimated 파라미터가 전달됩니다. reason은 이벤트를 발생시킨 카메라 이동의 원인입니다. NMFCameraUpdate.reason을 이용해 카메라 이동의 원인을 지정할 수 있으며, 이벤트 리스너 내에서 이 값을 이용해 어떤 원인에 의해 발생한 이벤트인지 판단할 수 있습니다. 제스처, 컨트롤 등 네이버 지도 SDK의 내장 기능에 의해 카메라가 이동한 경우 미리 정의된 음숫값으로 설정되며, 개발자가 임의의 양숫값을 지정할 수도 있습니다. 미리 정의되어 있는 원인은 다음과 같습니다.

다음은 카메라 변경 시 원인을 로깅하는 델리게이트 메서드와 원인을 지정해 카메라를 이동시키는 예제입니다.

func mapViewRegionIsChanging(_ mapView: NMFMapView, byReason reason: Int) {
    print("카메라 변경 - reason: \(reason)")
}

let cameraUpdate = NMFCameraUpdate(scrollTo: NMGLatLng(lat: 37.5666102, lng: 126.9783881))
cameraUpdate.animation = .easeIn
cameraUpdate.animationDuration = 2
cameraUpdate.reason = 1000

mapView.moveCamera(cameraUpdate)

Swift

func mapViewRegionIsChanging(_ mapView: NMFMapView, byReason reason: Int) {
    print("카메라 변경 - reason: \(reason)")
}

let cameraUpdate = NMFCameraUpdate(scrollTo: NMGLatLng(lat: 37.5666102, lng: 126.9783881))
cameraUpdate.animation = .easeIn
cameraUpdate.animationDuration = 2
cameraUpdate.reason = 1000

mapView.moveCamera(cameraUpdate)

Objective-C

- (void)mapViewRegionIsChanging:(NMFMapView *)mapView byReason:(NSInteger)reason {
    NSLog(@"카메라 변경 - reason : %ld", (long)reason);
}

NMFCameraUpdate *cameraUpdate = [NMFCameraUpdate cameraUpdateWithScrollTo:NMGLatLngMake(37.5666102, 126.9783881)];
cameraUpdate.animation = NMFCameraUpdateAnimationEaseIn;
cameraUpdate.animationDuration = 2;
cameraUpdate.reason = 1000;

[self.mapView moveCamera:cameraUpdate];

카메라 대기 이벤트

카메라의 움직임이 끝나 대기 상태가 되면 카메라 대기 이벤트가 발생합니다. -mapViewCameraIdle: 메서드로 카메라 대기 이벤트를 받을 수 있습니다. 카메라가 대기 상태가 되면 -mapViewCameraIdle:가 호출됩니다.

카메라는 다음과 같은 시점에 대기 상태가 된 것으로 간주되어 이벤트가 발생합니다.

  • 카메라가 애니메이션 없이 움직일 때. 단, 사용자가 제스처로 지도를 움직이는 경우 제스처가 완전히 끝날때까지(touchesEnded:가 발생할 때까지)는 연속적인 이동으로 간주되어 이벤트가 발생하지 않습니다.
  • 카메라 애니메이션이 완료될 때. 단, 카메라 애니메이션이 진행 중일 때 새로운 애니메이션이 발생하거나, 기존 카메라 이동의 completion으로 지정된 콜백 내에서 카메라 이동이 일어날 경우 연속적인 이동으로 간주되어 이벤트가 발생하지 않습니다.
  • NMFMapView.cancelTransitions()가 호출되어 카메라 애니메이션이 명시적으로 취소될 때.

다음은 카메라가 대기 상태가 되면 얼럿을 표시하는 예제입니다.

func mapViewCameraIdle(_ mapView: NMFMapView) {
    let alert = UIAlertController(title: "카메라 움직임 종료",
                                  message: nil,
                                  preferredStyle: .alert)
    present(alert, animated: true, completion: {
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.5, execute: {
            alert.dismiss(animated: true, completion: nil)
        })
    })
}

Swift

func mapViewCameraIdle(_ mapView: NMFMapView) {
    let alert = UIAlertController(title: "카메라 움직임 종료",
                                  message: nil,
                                  preferredStyle: .alert)
    present(alert, animated: true, completion: {
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.5, execute: {
            alert.dismiss(animated: true, completion: nil)
        })
    })
}

Objective-C

- (void)mapViewCameraIdle:(NMFMapView *)mapView {
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"카메라 움직임 종료" message:nil preferredStyle:UIAlertControllerStyleAlert];

    [self presentViewController:alert animated:true completion:^{
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5.0 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
            [alert dismissViewControllerAnimated:YES completion:nil];
        });
    }];
}

피봇

NMFCameraUpdate.pivot 속성을 사용해 피봇 지점을 지정할 수 있습니다. 피봇 지점은 화면의 왼쪽 위를 (0, 0), 오른쪽 아래를 (1, 1)로 삼는 비율값으로, 카메라를 움직일 때 기준점이 되는 화면상 지점을 의미합니다. 피봇 지점이 지정되면 이동, 줌 레벨 변경, 회전이 화면 중심이 아닌 해당 지점을 기준으로 이루어집니다.

예를 들어 피봇 지점을 (0.5, 0.8)로 지정하고 카메라를 이동하면, 카메라 이동이 완료된 후 (0.5, 0.8) 지점의 좌표가 카메라 이동의 대상 지점과 일치하게 됩니다. 동일한 피봇 지점을 지정하고 지도를 확대하면 지도의 중심이 아닌 (0.5, 0.8) 지점을 기준으로 지도가 확대됩니다. 따라서 피봇 지점을 지정하면 카메라 이동이 완료된 후 카메라의 위치가 카메라 이동에서 지정했던 위치와 다를 수 있습니다.

피봇은 카메라가 위치해야 하는 화면상 지점을 지정한다는 측면에서는 콘텐츠 패딩과 동일한 역할을 합니다. 그러나 NMFMapView의 속성인 콘텐츠 패딩과 달리 피봇은 NMFCameraUpdate의 속성이므로 하나의 카메라 변경에만 적용되며, 지도 객체에 영구적으로 영향을 미치지 않습니다.

다음은 피봇 지점을 (0.5, 0.8)로 지정하고 카메라를 이동시키는 예제입니다.

let cameraUpdate = NMFCameraUpdate(scrollTo: NMGLatLng(lat: 37.5666102, lng: 126.9783881))
cameraUpdate.pivot = CGPoint(x: 0.5, y: 0.8)

mapView.moveCamera(cameraUpdate)

Swift

let cameraUpdate = NMFCameraUpdate(scrollTo: NMGLatLng(lat: 37.5666102, lng: 126.9783881))
cameraUpdate.pivot = CGPoint(x: 0.5, y: 0.8)

mapView.moveCamera(cameraUpdate)

Objective-C

NMFCameraUpdate *cameraUpdate = [NMFCameraUpdate cameraUpdateWithScrollTo:NMGLatLngMake(37.5666102, 126.9783881)];
cameraUpdate.pivot = CGPointMake(0.5, 0.8);

[self.mapView moveCamera:cameraUpdate];

이동 제한

NMFMapView의 속성을 지정하면 카메라가 이동할 수 있는 영역과 최소 및 최대 줌 레벨을 제한할 수 있습니다.

최소 및 최대 줌 레벨

minZoomLevelmaxZoomLevel 속성을 지정하면 카메라의 최소 및 최대 줌 레벨을 제한할 수 있습니다.

다음은 카메라의 줌 레벨을 5~18 범위로 제한하는 예제입니다.

mapView.minZoomLevel = 5.0
mapView.maxZoomLevel = 18.0

Swift

mapView.minZoomLevel = 5.0
mapView.maxZoomLevel = 18.0

Objective-C

self.mapView.minZoomLevel = 5.0;
self.mapView.maxZoomLevel = 18.0;

카메라 영역 제한

extent 속성을 지정하면 카메라의 대상 지점을 영역 내로 제한할 수 있습니다. 카메라가 제한 영역을 벗어나도록 API를 호출하더라도 대상 지점이 영역 내로 조정됩니다.

다음은 카메라의 대상 지점을 한반도 인근으로 제한하는 예제입니다.

mapView.extent = NMGLatLngBounds(southWestLat: 31.43, southWestLng: 122.37, northEastLat: 44.35, northEastLng: 132)

Swift

mapView.extent = NMGLatLngBounds(southWestLat: 31.43, southWestLng: 122.37, northEastLat: 44.35, northEastLng: 132)

Objective-C

self.mapView.extent = NMGLatLngBoundsMake(31.43, 122.37, 44.35, 132);

카메라 영역을 제한할 때 최소 줌 레벨도 함께 제한하는 것이 좋습니다. 그렇지 않으면 지도가 축소되었을 때 제한 영역이 너무 작게 나타날 수 있습니다.

results matching ""

    No results matching ""