iOS 앱(Objective-C)에 지도 추가하기

1. 시작하기 전에

개요

이번 Codelab에서는 Objective-C에서 iOS 앱을 만들기 위해 Google Maps Platform을 사용할 때 필요한 사항을 모두 살펴봅니다. 설정부터 iOS용 Maps SDK 로드, 첫 번째 지도 표시, 마커 및 마커 클러스터링 작업, 지도에 그리기, 사용자 상호작용 처리에 이르기까지 모든 기본사항을 배우게 됩니다.

빌드할 내용

342520482a888519.png

본 Codelab에서는 다음 작업을 수행하는 iOS 앱을 만듭니다.

  • iOS용 Maps SDK와 iOS용 Maps SDK 유틸리티 라이브러리 로드
  • 지도 중앙에 오스트레일리아 시드니 표시
  • 시드니 주변의 100개 지점에 맞춤 마커 표시
  • 마커 클러스터링 구현
  • 마커를 클릭하면 지도 중앙을 재설정하고 원을 그리는 사용자 상호작용 사용 설정

학습 내용

  • Google Maps Platform 시작하기
  • iOS용 Maps SDK 및 iOS용 Google Maps SDK 유틸리티 라이브러리 로드하기
  • 지도 로드하기
  • 마커, 맞춤 마커 및 마커 클러스터링 사용하기
  • iOS용 Maps SDK 이벤트 시스템과 연계하여 사용자 상호작용 제공하기
  • 프로그래매틱 방식으로 지도 컨트롤하기
  • 지도에 그리기

기본 요건

본 Codelab을 완료하려면 아래 내용을 숙지해야 합니다. Google Maps Platform 사용에 익숙하다면 Codelab으로 건너뛰어도 됩니다.

필수 Google Maps Platform 제품

본 Codelab에서는 다음과 같은 Google Maps Platform 제품을 사용합니다.

  • iOS용 Maps SDK
  • iOS용 Google Maps SDK 유틸리티 라이브러리

Google Maps Platform 시작하기

Google Maps Platform을 처음 사용한다면 Google Maps Platform 시작하기 가이드를 따르거나 Google Maps Platform 시작하기 재생목록을 시청하여 다음 단계를 완료하세요.

  1. 결제 계정을 만듭니다.
  2. 프로젝트를 만듭니다.
  3. 이전 섹션에 표시된 Google Maps Platform API와 SDK를 사용 설정합니다.
  4. API 키를 생성합니다.

본 Codelab의 기타 요구사항

본 Codelab을 완료하려면 아래의 계정, 서비스 및 도구가 필요합니다.

  • 결제가 사용 설정된 Google Cloud Platform 계정
  • iOS용 Maps SDK가 사용 설정된 Google Maps Platform API 키
  • Objective-C에 대한 기본 지식
  • Xcode 12.0(타겟 SDK 12.0 이상)

2. 설정하기

아래의 사용 설정 단계에서 iOS용 Maps SDK를 사용 설정해야 합니다.

Google Maps Platform 설정하기

Google Cloud Platform 계정 및 결제가 사용 설정된 프로젝트가 없는 경우 Google Maps Platform 시작하기 가이드를 참고하여 결제 계정 및 프로젝트를 만듭니다.

  1. Cloud Console에서 프로젝트 드롭다운 메뉴를 클릭하고 이 Codelab에 사용할 프로젝트를 선택합니다.

  1. Google Cloud Marketplace에서 이 Codelab에 필요한 Google Maps Platform API 및 SDK를 사용 설정합니다. 이 동영상 또는 이 문서의 단계를 따릅니다.
  2. Cloud Console의 Credentials 페이지에서 API 키를 생성합니다. 이 동영상 또는 이 문서의 단계를 따릅니다. Google Maps Platform에 대한 모든 요청에서 API 키가 필요합니다.

프로젝트 스타터 템플릿 설정

본 Codelab을 시작하기 전에 다음을 수행하여 스타터 프로젝트 템플릿과 전체 솔루션 코드를 다운로드하세요.

  1. https://github.com/googlecodelabs/maps-platform-101-objc에서 본 Codelab용 GitHub 저장소를 다운로드하거나 포크하세요.

StarterApp 프로젝트는 /starter 디렉터리에 있으며 Codelab을 완료하는 데 필요한 기본 파일 구조를 포함하고 있습니다. 작업해야 하는 모든 항목은 /starter/StarterApp 디렉터리에 있습니다.

실행 중인 전체 솔루션 코드를 보려면 위의 설정 단계를 완료하고 /solution/SolutionApp 디렉터리에서 해당 솔루션을 확인하세요.

3. iOS용 Maps SDK 설치하기

iOS용 Maps SDK를 사용하려면 먼저 필요한 종속 항목을 설치해야 합니다. 이 과정은 두 단계로 구성되어 있습니다. Cocoapods 종속 항목 관리자에서 iOS용 Maps SDK와 iOS용 Maps SDK 유틸리티 라이브러리를 설치한 다음 SDK에 API 키를 제공하세요.

  1. iOS용 Maps SDK 및 iOS용 Maps SDK 유틸리티 라이브러리를 Podfile에 추가하세요.

본 Codelab에서는 Google 지도의 핵심 기능을 모두 제공하는 iOS용 Maps SDK와 지도를 보강하는 다양한 유틸리티(예: 마커 클러스터링)를 제공하는 지도 iOS 유틸리티 라이브러리를 모두 사용합니다.

시작하려면 Xcode(또는 선호하는 텍스트 편집기)에서 Pods > Podfile을 열고 iOS용 Maps SDK 및 유틸리티 라이브러리 종속 항목이 use_frameworks!에 포함되도록 파일을 업데이트하세요.

pod 'GoogleMaps'
pod 'Google-Maps-iOS-Utils'
  1. iOS용 Maps SDK 및 iOS용 Maps SDK 유틸리티 라이브러리 포드를 설치하세요.

종속 항목을 설치하려면 명령줄의 /starter 디렉터리에서 pod install을 실행하세요. CocoaPods는 자동으로 종속 항목을 다운로드하고 StarterApp.xcworkspace를 만듭니다. 3. 종속 항목이 설치되면 Xcode에서 StarterApp.xcworkspace를 열고 Command+R을 눌러 iPhone 시뮬레이터에서 앱을 실행하세요. 모두가 올바르게 설정되면 시뮬레이터가 실행되고 검은색 화면이 표시됩니다. 아직 아무것도 만들지 않았고 예정된 과정이니 걱정하지 않으셔도 됩니다. 4. AppDelegate.h에서 SDK를 가져오세요.

종속 항목이 설치되었으므로 SDK에 API 키를 제공할 차례입니다. 먼저, #import "AppDelegate.h" 가져오기 문 아래에 다음을 추가하여 iOS용 Maps SDK를 종속 항목으로 가져오세요.

@import GoogleMaps;
  1. iOS SDK 가져오기 문 아래에서 API 키에 설정된 값으로 NSString 상수를 선언하세요.
static NSString *const kMapsAPIKey = @"YOUR API KEY";
  1. application: didFinishLaunchingWithOptions:GMSServices에서 provideAPIKey를 호출하여 API 키를 iOS SDK에 전달하세요.
- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [GMSServices provideAPIKey:kMapsAPIKey];
  return YES;
}

업데이트된 AppDelegate.m 파일은 다음과 같이 표시됩니다.

#import "AppDelegate.h"
@import GoogleMaps;

static NSString *const kMapsAPIKey = @"YOUR API KEY";

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [GMSServices provideAPIKey:kMapsAPIKey];
  return YES;
}
@end

Podfile은 다음과 같이 표시됩니다.

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '11.0'

target 'StarterApp' do
  use_frameworks!

pod 'GoogleMaps', '5.1.0.0'
pod 'Google-Maps-iOS-Utils', '3.4.0'

end

이제 종속 항목이 설치되고 API 키가 제공되었으므로 iOS용 Maps SDK를 호출할 수 있습니다.

4. 지도 표시하기

첫 지도를 표시할 차례입니다.

iOS용 Maps SDK에서 가장 흔히 사용되는 부분은 GMSMapView 클래스입니다. 이 클래스에서는 지도 인스턴스를 생성 및 조작할 수 있는 많은 메서드가 제공됩니다. 아래의 과정을 따르세요.

  1. ViewController.m을 여세요.

여기에서 본 Codelab의 나머지 작업 전체를 수행합니다. 뷰 컨트롤러의 loadViewviewDidLoad 수명 주기 이벤트가 이미 스텁 처리되고 있음을 확인합니다. 2. 파일 상단에 다음을 추가하여 iOS용 Maps SDK를 가져오세요.

@import GoogleMaps;
  1. GMSMapView를 저장할 ViewController 인스턴스 변수를 선언하세요.

GMSMapView의 인스턴스는 본 Codelab 전체에서 사용할 기본 객체이며, 다양한 뷰 컨트롤러 수명 주기 메서드에서 이를 참조하고 그에 따라 조치를 취합니다. 이러한 기본 객체를 사용하려면 이 객체를 저장하는 인스턴스 변수를 선언하도록 ViewController 구현을 업데이트하세요.

@implementation ViewController {
  GMSMapView *_mapView;
}
  1. loadView에서 GMSCameraPosition의 인스턴스를 만드세요.

GMSCameraPosition은 지도의 중앙에 표시할 위치와 화면의 확대/축소 수준을 정의합니다. 이 코드는 cameraWithLatitude:longitude:zoom: 메서드를 호출하여 오스트레일리아 시드니의 위도 -33.86, 경도 151.20 지점을 지도 중앙에 확대/축소 수준 12로 표시합니다.

GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-33.86 longitude:151.20 zoom:12];
  1. loadView에서 GMSMapView의 인스턴스를 만들어 지도를 인스턴스화하세요.

새 지도 인스턴스를 만들려면 mapWithFrame:camera:를 호출하세요. 프레임이 CGRectZero로 설정된 방식에 유의해야 합니다. 이 코드는 뷰 컨트롤러 내 (0,0) 지점의 너비 0, 높이 0 프레임을 지정하는 iOS CGGeometry 라이브러리에서 가져온 전역 변수입니다. 카메라는 조금 전에 생성한 카메라 위치로 설정됩니다.

실제로 지도를 표시하려면 뷰 컨트롤러의 루트 뷰를 _mapview로 설정하세요. 그러면 지도가 전체 화면으로 표시됩니다.

_mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera];
self.view = _mapView;
  1. GMSMapViewDelegate를 뷰 컨트롤러로 설정하세요.

지도뷰 대리자를 구현하면 GMSMapView 인스턴스에서 발생하는 사용자 상호작용의 이벤트를 처리할 수 있습니다. 이 과정은 이후 단계에서 필요합니다.

먼저, GMSMapViewDelegate:의 프로토콜을 준수하도록 ViewController의 인터페이스를 업데이트하세요.

@interface ViewController ()<GMSMapViewDelegate>

그런 다음, 아래의 코드를 추가하여 GMSMapViewDelegateViewController로 설정하세요.

_mapView.delegate = self;

이제 iOS 시뮬레이터(Command+R)에서 앱을 새로고침하면 지도가 표시됩니다.

2e6ebac422323aa6.png

이상으로 GMSMapView의 인스턴스를 통해 오스트레일리아 시드니를 지도 중앙에 표시하는 방법에 대해 알아보았습니다.

이제 ViewController.m 파일이 다음과 같이 표시됩니다.

#import "ViewController.h"
#import "LocationGenerator.h"
@import GoogleMaps;

@interface ViewController ()<GMSMapViewDelegate>
@end

@implementation ViewController {
  GMSMapView *_mapView;
}

- (void)loadView {
  [super loadView];
  GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-33.86 longitude:151.20 zoom:12];
  _mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera];
  self.view = _mapView;
  _mapView.delegate = self;
}

5. 클라우드 기반 지도 스타일 지정 (선택사항)

클라우드 기반 지도 스타일 지정을 사용하여 지도 스타일을 맞춤설정할 수 있습니다.

지도 ID 만들기

연결된 지도 스타일이 있는 지도 ID를 아직 만들지 않은 경우 지도 ID 가이드를 참고하여 다음 단계를 완료하세요.

  1. 지도 ID 만들기
  2. 지도 ID를 지도 스타일에 연결하기

앱에 지도 ID 추가하기

이전 단계에서 만든 지도 ID를 사용하려면 ViewController.m 파일을 열고 loadView 메서드 내에서 GMSMapID 객체를 만들고 지도 ID를 제공합니다. 다음으로, GMSMapID 객체를 매개변수로 제공하여 GMSMapView 인스턴스화를 수정합니다.

ViewController.m

- (void)loadView {
    GMSMapID *mapID = [[GMSMapID alloc] initWithIdentifier:@"YOUR_MAP_ID"];
    _mapView = [GMSMapView mapWithFrame:CGRectZero mapID:mapID camera:camera];
    // ...
}

그런 다음 앱을 실행하여 선택한 스타일로 지도를 확인합니다.

6. 지도에 마커 추가하기

개발자가 iOS용 Maps SDK를 많은 용도로 사용하고 있는데, 지도에 마커를 추가하는 경우가 가장 많습니다. 마커는 지도에 특정 지점을 표시하는 기능이며, 사용자 상호작용을 처리하는 일반적인 UI 요소입니다. Google 지도를 사용해 본 적이 있다면 다음과 같은 기본 마커에 익숙할 것입니다.

590815267846f166.png

이 단계에서는 GMSMarker 클래스를 이용해 지도에 마커를 넣는 방법을 알아보겠습니다.

마커는 뷰 컨트롤러의 loadView 수명 주기 이벤트에 있는 이전 단계에서 지도가 로드된 후에만 지도에 넣을 수 있습니다. 따라서 뷰와 지도가 로드된 후 호출되는 viewDidLoad 수명 주기 이벤트의 단계를 완료하게 됩니다.

  1. CLLocationCoordinate2D 객체를 정의하세요.

CLLocationCoordinate2D는 iOS CoreLocation 라이브러리에서 제공하는 구조이며, 설정된 위도와 경도의 지리적 위치를 정의합니다. 첫 번째 마커를 만들려면 CLLocationCoordinate2D 객체를 정의하고 위도와 경도를 지도 중앙으로 설정하세요. camera.target.latitudecamera.target.longitude 속성을 사용하여 지도뷰에서 지도 중앙의 좌표에 액세스할 수 있습니다.

CLLocationCoordinate2D mapCenter = CLLocationCoordinate2DMake(_mapView.camera.target.latitude, _mapView.camera.target.longitude);
  1. GMSMarker의 인스턴스를 생성하세요.

iOS용 Maps SDK는 GMSMarker 클래스를 제공합니다. GMSMarker의 각 인스턴스는 지도상의 개별 마커를 나타내며, markerWithPosition:을 호출하고 CLLocationCoordinate2D 객체를 전달하여 지도에 마커를 표시할 위치를 SDK에 알리면서 생성됩니다.

GMSMarker *marker = [GMSMarker markerWithPosition:mapCenter];
  1. 맞춤 마커 아이콘을 설정하세요.

Google 지도의 기본 빨간색 핀 마커는 그 자체로 멋지지만, 이 마커를 맞춤설정하여 지도에 표시할 수도 있습니다. iOS용 Maps SDK에서는 맞춤 마커 사용이 매우 쉽습니다. StarterApp 프로젝트에 있는 'custom_pin.png'라는 이미지를 사용할 수 있으며, 다른 원하는 이미지를 사용해도 됩니다.

맞춤 마커를 설정하려면 마커의 icon 속성을 UIImage의 인스턴스로 설정하세요.

marker.icon = [UIImage imageNamed:@"custom_pin.png"];
  1. 마커를 지도에 렌더링하세요.

마커가 생성되지만, 지도에 표시되지는 않습니다. 지도에 표시하려면 GMSMarker 인스턴스의 map 속성을 GMSMapView의 인스턴스로 설정하세요.

marker.map = _mapView;

이제 앱을 새로고침하면 지도에 마커가 표시됩니다.

a4ea8724f8c5ba20.png

이 섹션에서는 GMSMarker 클래스의 인스턴스를 생성하고 지도뷰에 적용하여 지도에 마커를 표시해 보았습니다. 이제 ViewController.m의 업데이트된 viewDidLoad 수명 주기 이벤트가 다음과 같이 표시됩니다.

- (void)viewDidLoad {
  [super viewDidLoad];

  CLLocationCoordinate2D mapCenter = CLLocationCoordinate2DMake(_mapView.camera.target.latitude, _mapView.camera.target.longitude);
  GMSMarker *marker = [GMSMarker markerWithPosition:mapCenter];
  marker.icon = [UIImage imageNamed:@"custom_pin.png"];
  marker.map = _mapView;
}

7. 마커 클러스터링 사용 설정하기

마커를 많이 사용하거나 여러 마커가 서로 너무 가까이 있으면 마커가 겹치거나 복잡하게 보이면서 사용자 경험이 저하될 수 있습니다. 예를 들어 두 마커가 서로 너무 가까이 있으면 다음과 같이 표시될 수 있습니다.

6e39736160c6bce4.png

이러한 경우에 마커 클러스터링이 사용됩니다. 마커 클러스터링은 서로 가까이 있는 여러 마커를 아이콘 하나로 그룹화하는 기능이며, 자주 사용됩니다. 그룹화의 정도는 화면의 확대/축소 수준에 따라 달라집니다. 아래 그림을 참고하세요.

4abb38cd97cab3f1.png

마커 클러스터링의 알고리즘이 지도의 보이는 영역을 그리드로 나눈 다음, 같은 셀에 있는 여러 아이콘을 클러스터링합니다. 실제로는 Google Maps Platform팀에서 iOS용 Google Maps SDK 유틸리티 라이브러리라는 유용한 오픈소스 유틸리티 라이브러리를 만들었으니 마커 클러스터링에 신경쓰지 않으셔도 됩니다. 이 라이브러리의 핵심 기능 중 하나가 바로 자동 마커 클러스터링입니다. Google Maps Platform 문서에서 마커 클러스터링에 대해 자세히 알아보거나 GitHub에서 iOS 유틸리티 라이브러리의 소스를 확인해 보세요.

  1. 지도에 마커를 많이 추가하세요.

마커 클러스터링이 어떻게 작동하는지를 제대로 확인하려면 지도에 마커가 많아야 합니다. 마커를 쉽게 추가할 수 있도록 LocationGenerator.m의 스타터 프로젝트에서 편리한 마커 생성기가 제공됩니다.

지도에 마커를 원하는 만큼 추가하려면 이전 단계의 코드 아래에 있는 뷰 컨트롤러의 viewDidLoad 수명 주기에서 generateMarkersNear:count:를 호출하세요. 이 메서드는 CLLocationCoordinate2D 객체에 지정된 좌표 주변의 무작위 위치에 count에서 지정된 수만큼의 마커를 생성합니다. 이때 앞에서 만든 mapCenter 변수를 전달하기만 하면 마커가 NSArray로 반환됩니다.

NSArray<GMSMarker *> *markerArray = [LocationGenerator generateMarkersNear:mapCenter count:100];
  1. Google iOS용 Maps SDK 유틸리티 라이브러리를 가져오세요.

지도 iOS 유틸리티 라이브러리를 프로젝트의 종속 항목으로 추가하려면 ViewController.m 상단의 종속 항목 목록에 다음을 추가하세요.

@import GoogleMapsUtils;
  1. 마커 클러스터러를 구성하세요.

마커 클러스터러를 사용하려면 이 기능의 작동 방식을 구성하기 위한 클러스터링 알고리즘, 아이콘 생성기, 렌더기를 제공해야 합니다. 알고리즘은 마커 클러스터링 방식(예: 동일한 클러스터에 넣을 마커 간의 거리)을 결정합니다. 아이콘 생성기는 다양한 확대/축소 수준에서 사용할 클러스터 아이콘을 제공합니다. 렌더기는 지도에서 클러스터 아이콘의 실제 렌더링을 처리합니다.

원할 경우 이를 모두 처음부터 작성해도 되지만, 손쉽게 처리할 수 있도록 지도 iOS 유틸리티 라이브러리에서 기본 구현을 제공합니다. 다음을 추가하세요.

id<GMUClusterAlgorithm> algorithm = [[GMUNonHierarchicalDistanceBasedAlgorithm alloc] init];

id<GMUClusterIconGenerator> clusterIconGenerator = [[GMUDefaultClusterIconGenerator alloc] init];

id<GMUClusterRenderer> renderer = [[GMUDefaultClusterRenderer alloc] initWithMapView:_mapView clusterIconGenerator:clusterIconGenerator];
  1. GMUClusterManager의 인스턴스를 생성하세요.

GMUClusterManager는 개발자가 지정한 알고리즘, 아이콘 생성기, 렌더기를 사용하여 마커 클러스터링을 구현하는 클래스입니다. 렌더기를 만들고 지도뷰에서 사용할 수 있게 하려면 먼저 ViewController 구현에 인스턴스 변수를 추가하여 클러스터 관리자 인스턴스를 저장하세요.

@implementation ViewController {
  GMSMapView *_mapView;
  GMUClusterManager *_clusterManager;
}

그런 다음, viewDidLoad 수명 주기 이벤트에서 GMUClusterManager의 인스턴스를 생성하세요.

_clusterManager = [[GMUClusterManager alloc] initWithMap:_mapView algorithm:algorithm renderer:renderer];
  1. 마커를 추가하고 마커 클러스터러를 실행하세요.

이제 마커 클러스터러 인스턴스가 구성되었으므로 addItems:를 호출하여 클러스터링할 마커 배열을 클러스터 관리자에 전달한 다음 cluster를 호출하여 클러스터러를 실행하기만 하면 됩니다.

[_clusterManager addItems:markerArray];
[_clusterManager cluster];

앱을 새로고침하면 많은 마커가 깔끔하게 클러스터링된 것을 볼 수 있습니다. 지도에서 손가락을 벌리거나 모으면서 화면에 다양한 수준의 확대/축소를 적용하고 마커 클러스터가 제대로 조정되는지 확인하세요.

c49383b07752bfc4.png

이상으로 iOS용 Google Maps SDK 유틸리티 라이브러리에 있는 마커 클러스터러의 인스턴스를 구성한 다음 이를 이용해 지도에서 100개의 마커를 클러스터링해 보았습니다. 이제 viewDidLoad 수명 주기 이벤트ViewController.m가 다음과 같이 표시됩니다.

- (void)viewDidLoad {
  [super viewDidLoad];

  CLLocationCoordinate2D mapCenter = CLLocationCoordinate2DMake(_mapView.camera.target.latitude,
                                                                _mapView.camera.target.longitude);
  GMSMarker *marker = [GMSMarker markerWithPosition:mapCenter];
  marker.icon = [UIImage imageNamed:@"custom_pin.png"];
  marker.map = _mapView;
  NSArray<GMSMarker *> *markerArray = [LocationGenerator generateMarkersNear:mapCenter count:100];

  id<GMUClusterAlgorithm> algorithm = [[GMUNonHierarchicalDistanceBasedAlgorithm alloc] init];
  id<GMUClusterIconGenerator> clusterIconGenerator = [[GMUDefaultClusterIconGenerator alloc] init];
  id<GMUClusterRenderer> renderer = [[GMUDefaultClusterRenderer alloc] initWithMapView:_mapView clusterIconGenerator:clusterIconGenerator];
  _clusterManager = [[GMUClusterManager alloc] initWithMap:_mapView algorithm:algorithm renderer:renderer];

  [_clusterManager addItems:markerArray];
  [_clusterManager cluster];
}

8. 사용자 상호작용 추가하기

여러 마커를 표시하고 마커 클러스터링이 사용되는 깔끔한 지도를 만들었습니다. 이번 단계에서는 지도의 사용자 경험 개선을 위해 앞서 뷰 컨트롤러에 설정한 GMSMapViewDelegate를 이용해 사용자 상호작용 처리를 추가해 보겠습니다.

iOS용 Maps SDK는 지도뷰 대리자(다양한 사용자 상호작용이 발생할 때 코드를 실행할 수 있게 해주는 이벤트 핸들러 포함)를 통해 구현된 포괄적인 이벤트 시스템을 제공합니다. 예를 들어 지도뷰 대리자에는 사용자의 지도 및 마커 클릭, 지도뷰 이동, 확대/축소 등의 상호작용을 위한 코드 실행을 트리거할 수 있게 해주는 메서드가 포함됩니다.

이 단계에서는 사용자가 탭한 마커를 지도 화면의 중앙에 표시하는 프로그래밍에 대해 알아보겠습니다.

  1. 마커 탭 리스너를 구현하세요.

사용자가 앞서 생성한 마커 중 하나를 탭할 때 또는 마커 클러스터를 탭할 때마다 mapView:didTapMarker가 호출됩니다(내부적으로 마커 클러스터는 GMSMarker의 인스턴스로 구현됨).

이벤트 리스너를 구현하려면 먼저 ViewController.m 하단에서 end 문 전까지 스텁 처리하세요.

메서드에서 NO가 반환되는 것을 볼 수 있습니다. 이렇게 하면 기본 GMSMarker 기능(예: 구성된 경우, 이벤트 핸들러 코드 실행 후 정보 창 표시)을 계속 실행하라고 iOS SDK에 지시하게 됩니다.

- (BOOL)mapView:(GMSMapView *)mapView didTapMarker:(GMSMarker *)marker {

  return NO;
}
  1. 마커 또는 마커 클러스트를 탭하면 탭 이벤트를 처리하고 지도 중앙이 재설정되도록 카메라를 이동합니다.

mapView:didTapMarker는 호출될 경우 탭한 GMSMarker의 인스턴스를 전달하므로 코드에서 이를 처리할 수 있게 됩니다. 이 인스턴스를 이용해 지도의 중앙을 재설정할 수 있는데, 이벤트 핸들러 내에서 지도뷰의 animateToLocation:을 호출하고 position 속성에서 사용할 수 있는 마커 인스턴스의 위치를 전달하면 됩니다.

[_mapView animateToLocation:marker.position];
  1. 마커 클러스터는 탭하면 확대됩니다.

일반적인 UX 패턴에서는 마커 클러스터를 탭했을 때 클러스터가 확대됩니다. 이렇게 되면 화면 확대 수준이 낮을 때 클러스터가 커지므로 클러스터링된 마커를 볼 수 있습니다.

앞서 언급했듯이 사실 마커 클러스터 아이콘은 맞춤 아이콘을 이용해 GMSMarker를 구현한 것에 불과합니다. 마커 또는 클러스터 클러스터를 탭했는지는 어떻게 알 수 있을까요? 마커 클러스터러 관리자가 새 클러스터 아이콘을 만들 때 GMSMarker의 인스턴스를 구현하여 GMUCluster. 프로토콜을 준수합니다. 이벤트 핸들러에 전달된 마커가 이 프로토콜을 준수하는지는 조건을 이용해 확인할 수 있습니다.

클러스터를 탭한 것을 프로그래매틱 방식으로 파악했으면 지도뷰 인스턴스에서 animateToZoom:을 호출하고 확대/축소를 현재보다 한 단계 높은 수준으로 설정하세요. 현재의 확대/축소 수준은 camera.zoom 속성의 지도뷰 인스턴스에서 사용할 수 있습니다.

아래의 코드가 어떻게 YES를 반환하는지도 확인하세요. 이러한 반환이 있으면 이벤트 처리를 완료했고 핸들러에서 추가 코드를 실행하지 않을 것임을 이벤트 핸들러에 알립니다. 이렇게 하는 이유 중 하나는 기본 GMSMarker 객체가 기본 동작의 나머지를 실행하지 못하게 하기 위함입니다. 예를 들어 클러스터 아이콘을 탭할 경우에는 정보 창 표시가 적절하지 않습니다.

if ([marker.userData conformsToProtocol:@protocol(GMUCluster)]) {
    [_mapView animateToZoom:_mapView.camera.zoom +1];
    return YES;
}

앱을 새로고침하고 마커와 마커 클러스터 몇 개를 탭해 보세요. 마커나 마커 클러스터를 탭하면 해당 요소가 지도의 중앙에 표시됩니다. 마커 클러스터를 탭하면 지도가 한 단계씩 확대되고 마커 클러스터가 커지면서 클러스터링된 마커가 표시됩니다.

이상으로 마커 탭 리스너를 구현해 보았으며, 탭한 요소를 지도의 중앙에 표시하고 이 요소가 마커 클러스터 아이콘인 경우 확대하는 이벤트를 처리하는 방법도 살펴봤습니다.

mapView:didTapMarker 메서드가 다음과 같이 표시됩니다.

- (BOOL)mapView:(GMSMapView *)mapView didTapMarker:(GMSMarker *)marker {
  [_mapView animateToLocation:marker.position];

  if ([marker.userData conformsToProtocol:@protocol(GMUCluster)]) {
    [_mapView animateToZoom:_mapView.camera.zoom +1];
    return YES;
  }

  return NO;
}

9. 지도에 그리기

지금까지 100개의 무작위 지점에 마커를 표시하고 사용자 상호작용을 처리하는 시드니 지도를 만들었습니다. 이번 Codelab의 마지막 단계에서는 iOS용 Maps SDK의 그리기 기능을 이용해 지도 환경에 유용한 기능을 추가해 보겠습니다.

시드니 관광객이 이용하는 지도라면 마커를 클릭할 때 주변 반경을 시각적으로 보여주는 기능이 유용할 것입니다. 이 기능이 있으면 클릭한 마커 위치에서 무난하게 걸어갈 수 있는 지점을 쉽게 찾을 수 있습니다.

iOS SDK에는 지도에 정사각형 및 기타 다각형, 선, 원 등을 그릴 수 있는 여러 기능이 있습니다. 예를 들어 클릭한 마커의 반경 800미터(약 0.5마일) 지역을 표시하는 원을 렌더링할 수 있습니다.

  1. ViewController 구현에 _circ 인스턴스 변수를 추가하세요.

이 인스턴스 변수는 가장 최근에 그려진 원을 저장하는 데 사용되며, 다른 원이 그려지기 전에 기존 원은 삭제됩니다. 사실 사용자에게는 별다른 도움이 되지 않는 기능입니다. 마커를 탭할 때마다 반경을 나타내는 원이 표시되면 번잡한 느낌을 줄 수 있습니다.

이 문제를 해결하기 위해 다음과 같이 ViewController 구현을 업데이트하세요.

@implementation ViewController {
  GMSMapView *_mapView;
  GMUClusterManager *_clusterManager;
  GMSCircle *_circ;
}
  1. 마커를 탭하면 원이 그려집니다.

mapView:didTapMarker 메서드 하단에 다음 코드를 추가하여 iOS SDK에 있는 GMSCircle 클래스의 인스턴스를 만드세요. circleWithPosition:radius:를 호출하고 탭한 마커의 위치를 전달하여 800미터 반경 원을 새로 그리는 인스턴스이며, 앞서 지도의 중앙을 재설정할 때의 방법과 동일합니다.

_circ = [GMSCircle circleWithPosition:marker.position radius:800];
  1. 원의 스타일을 지정하세요.

기본적으로 GMSCircle은 검은색 획과 투명 채움이 적용된 원을 그립니다. 이렇게 하면 반경이 표시되지만, 깔끔하지 않아 보기에 불편할 수 있습니다. 그런 다음, 스타일이 깔끔해지도록 원의 fillColor 속성에 UIColor를 할당하여 원의 채움 색상을 지정하세요. 아래의 코드는 투명도가 50%인 회색 채움을 적용합니다.

_circ.fillColor = [UIColor colorWithRed: 0.67 green: 0.67 blue: 0.67 alpha: 0.5];
  1. 지도에서 원을 렌더링하세요.

앞서 마커를 만들 때처럼, GMSCircle의 인스턴스를 만드는 것만으로는 충분하지 않습니다. 지도뷰 인스턴스를 원의 map 속성에 할당하기만 하면 됩니다.

_circ.map = _mapView;
  1. 이전에 렌더링된 원은 삭제하세요.

앞서 언급했듯이, 지도에 원이 계속 추가되면 사용자 경험이 저해될 수 있습니다. 이전 탭 이벤트에서 렌더링된 원을 삭제하려면 _circmap 속성을 mapView:didTapMarker 상단에서 nil로 설정하세요.

_circ.map = nil;

앱을 새로고침하고 마커를 탭하세요. 마커를 탭할 때마다 새 원이 그려지고, 이전에 렌더링된 원은 삭제됩니다.

342520482a888519.png

이상으로 마커를 탭할 때마다 원을 렌더링하는 GMSCircle 클래스를 사용해 보았습니다.

mapView:didTapMarker 메서드는 다음과 같이 표시됩니다.

- (BOOL)mapView:(GMSMapView *)mapView didTapMarker:(GMSMarker *)marker {
  _circ.map = nil;
  [_mapView animateToLocation:marker.position];

  if ([marker.userData conformsToProtocol:@protocol(GMUCluster)]) {
    [_mapView animateToZoom:_mapView.camera.zoom +1];
    return YES;
  }

  _circ = [GMSCircle circleWithPosition:marker.position radius:800];
  _circ.fillColor = [UIColor colorWithRed: 0.67 green: 0.67 blue: 0.67 alpha: 0.5];
  _circ.map = _mapView;
  return NO;
}

10. 축하합니다

지금까지 Google Maps Platform을 이용해 iOS용 Maps SDK 로드, 지도 로드, 마커 작업, 지도에서 컨트롤 및 그리기 사용, 사용자 상호작용 추가 등을 하면서 첫 번째 iOS 앱을 성공적으로 만들었습니다.

완성된 코드를 보려면 완료된 프로젝트가 /solution 디렉터리인지 확인하세요.

다음 단계

본 Codelab에서는 iOS용 Maps SDK로 처리할 수 있는 기본사항에 대해서만 알아보았습니다. 다음과 같은 기능을 지도에 추가해 보세요.

  • 지도 유형을 변경하여 위성 지도, 하이브리드 지도 또는 지형 지도를 표시합니다.
  • 확대/축소, 지도 컨트롤과 같은 기타 사용자 상호작용을 맞춤설정합니다.
  • 마커를 클릭하면 정보가 표시되도록 정보 창을 추가합니다.
  • 다양한 Google Maps Platform 장소 기능과 데이터를 앱에 추가합니다(iOS용 Places SDK 참고).

Google Maps Platform을 사용하는 방법을 더 많이 알아보려면 아래의 온라인 리소스를 참고하세요.