1. 시작하기 전에
이 Codelab에서는 SwiftUI와 함께 iOS용 Maps SDK를 사용하는 방법을 알아봅니다.

사전 준비 사항
- Swift 기본 지식
- SwiftUI 기본 지식
수행할 작업
- SwiftUI를 사용하여 iOS용 Maps SDK를 사용하고 iOS 앱에서 Google 지도를 iOS 앱에 추가합니다.
- 지도에 마커 추가하기.
- SwiftUI 뷰에서
GMSMapView객체로 상태를 전달합니다.
필요한 사항
- Xcode 11.0 이상
- 결제가 사용 설정된 Google 계정
- iOS용 Maps SDK
- Carthage
2. 설정하기
다음 사용 설정 단계를 진행하려면 iOS용 Maps SDK를 사용 설정합니다.
Google Maps Platform 설정
Google Cloud Platform 계정 및 결제가 사용 설정된 프로젝트가 없는 경우 Google Maps Platform 시작하기 가이드를 참고하여 결제 계정 및 프로젝트를 만듭니다.
- Cloud Console에서 프로젝트 드롭다운 메뉴를 클릭하고 이 Codelab에 사용할 프로젝트를 선택합니다.

- Google Cloud Marketplace에서 이 Codelab에 필요한 Google Maps Platform API 및 SDK를 사용 설정합니다. 이렇게 하려면 이 동영상 또는 이 문서의 단계를 따릅니다.
- Cloud Console의 Credentials 페이지에서 API 키를 생성합니다. 이 동영상 또는 이 문서의 단계를 따릅니다. Google Maps Platform으로 전송되는 모든 요청에는 API 키가 필요합니다.
3. 시작 코드 다운로드하기
빠르게 시작할 수 있도록 이 Codelab을 따라하는 데 도움이 되는 시작 코드가 있습니다. 해법으로 바로 넘어갈 수 있지만 모든 단계를 따라하면서 직접 빌드하려면 계속 읽으시기 바랍니다.
git을 설치한 경우 저장소를 클론합니다.
git clone https://github.com/googlecodelabs/maps-ios-swiftui.git
또는 다음 버튼을 클릭하여 소스 코드를 다운로드할 수도 있습니다.
- 코드를 받으면 터미널
cd안에서starter/GoogleMapsSwiftUI디렉터리로 이동합니다. carthage update --platform iOS를 실행하여 iOS용 Maps SDK를 다운로드하세요.- 마지막으로 Xcode에서
GoogleMapsSwiftUI.xcodeproj파일을 엽니다.
4. 코드 개요
다운로드한 시작 프로젝트에서는 다음 클래스가 제공되고 구현되어 있습니다.
AppDelegate- 애플리케이션의UIApplicationDelegate입니다. 여기에서 iOS용 Maps SDK가 초기화됩니다.City- 도시를 나타내는 구조체 (도시의 이름과 좌표 포함)MapViewController- Google 지도 (GMSMapView가 포함된 간단한 UIKitUIViewController)SceneDelegate-ContentView가 인스턴스화되는 애플리케이션의UIWindowSceneDelegate입니다.
또한 다음 클래스에는 부분 구현이 있으며 이 Codelab을 마칠 때까지 직접 완료합니다.
ContentView- 앱이 포함된 최상위 SwiftUI 뷰입니다.MapViewControllerBridge- UIKit 뷰를 SwiftUI 뷰에 연결하는 클래스입니다. 특히 SwiftUI에서MapViewController에 액세스할 수 있게 하는 클래스입니다.
5. SwiftUI 사용과 UIKit 비교
SwiftUI는 iOS 애플리케이션 개발을 위한 UIKit의 대체 UI 프레임워크로 iOS 13에서 도입되었습니다. SwiftUI는 이전 UIKit과 비교할 때 여러 가지 장점이 있습니다. 다음과 같습니다...
- 상태가 변경되면 뷰가 자동으로 업데이트됩니다. 상태라는 객체를 사용하면 포함된 기본 값을 변경하면 UI가 자동으로 업데이트됩니다.
- 실시간 미리보기를 사용하면 개발 속도를 높일 수 있습니다. 실시간 미리보기는 Xcode를 미리 볼 수 있으므로 SwiftUI 뷰의 미리보기를 쉽게 볼 수 있도록 코드를 빌드하고 에뮬레이터에 배포할 필요성을 최소화합니다.
- 정보 소스는 Swift에 있습니다. SwiftUI의 모든 뷰는 Swift에서 선언되므로 인터페이스 빌더를 더 이상 사용할 필요가 없습니다.
- UIKit와 상호 운용됩니다. UIKit와의 상호 운용성은 기존 앱이 SwiftUI를 기존 뷰와 점진적으로 사용할 수 있게 해줍니다. 또한 iOS용 Maps SDK와 같이 SwiftUI를 아직 지원하지 않는 라이브러리도 SwiftUI에서 사용할 수 있습니다.
몇 가지 단점도 있습니다.
- SwiftUI는 iOS 13 이상에서만 사용할 수 있습니다.
- Xcode 미리보기에서는 뷰 계층 구조를 검사할 수 없습니다.
SwiftUI 상태 및 데이터 흐름
SwiftUI는 선언적 접근 방식을 사용하여 UI를 만드는 새로운 방법을 제공합니다. SwiftUI에 뷰가 다양한 다양한 상태와 함께 어떻게 표시되는지 확인할 수 있으며, 나머지는 시스템에서 자동으로 처리합니다. SwiftUI는 이벤트 또는 사용자 작업에 의해 기본 상태가 변경될 때마다 뷰 업데이트를 처리합니다. 이러한 설계를 일반적으로 단방향 데이터 흐름이라고 합니다. 이 설계의 세부사항은 이 Codelab에서 다루지 않지만, Apple의 상태 및 데이터 흐름 문서에서 이 내용이 어떻게 작동하는지 읽어보는 것이 좋습니다.
UIViewRepresentable 또는 UIViewControllerRepresentable를 사용하여 UIKit 및 SwiftUI 연결
iOS용 Maps SDK는 UIKit를 기반으로 빌드되지만 아직 SwiftUI 호환 뷰를 제공하지 않으므로 SwiftUI에서 사용하려면 UIViewRepresentable 또는 UIViewControllerRepresentable를 준수해야 합니다. 이러한 프로토콜을 사용하면 SwiftUI에 각각 UIKit 빌드 UIView 및 UIViewController를 포함할 수 있습니다. 두 프로토콜을 사용하여 SwiftUI 뷰에 Google 지도를 추가할 수 있지만, 다음 단계에서는 UIViewControllerRepresentable를 사용하여 지도를 포함하는 UIViewController를 살펴보겠습니다.
6. 지도 추가
이 섹션에서는 SwiftUI 뷰에 Google 지도를 추가합니다.

API 키 추가하기
이전 단계에서 만든 API 키를 iOS용 Maps SDK에 제공해야 계정을 앱에 표시되는 지도와 연결할 수 있습니다.
API 키를 제공하려면 AppDelegate.swift 파일을 탐색하고 application(_, didFinishLaunchingWithOptions) 메서드로 이동합니다. 현재 SDK는 'YOUR_API_KEY' 문자열로 GMSServices.provideAPIKey()를 통해 초기화됩니다. 이 문자열을 API 키로 바꿉니다. 이 단계를 완료하면 애플리케이션이 시작될때 iOS용 Maps SDK가 초기화됩니다.
MapViewControllerBridge를 사용하여 Google 지도 추가
이제 API 키가 SDK에 제공되고 있으므로 다음 단계에서는 앱에 지도를 표시합니다.
시작 코드에 제공된 뷰 컨트롤러 MapViewController에는 현재 뷰에 GMSMapView가 포함되어 있습니다. 그러나 이 뷰 컨트롤러는 UIKit에서 생성되었으므로 이 클래스를 ContentView 내에서 사용할 수 있도록 이 클래스를 SwiftUI에 연결해야 합니다. 방법은 다음과 같습니다.
- Xcode에서
MapViewControllerBridge파일을 엽니다.
이 클래스는 SwiftUI 뷰로 사용할 수 있도록 UIKit UIViewController를 래핑하는 데 필요한 프로토콜인 UIViewControllerRepresentable을 준수합니다. 즉, 이 프로토콜을 준수하면 UIKit 뷰를 SwiftUI 뷰로 연결할 수 있습니다. 이 프로토콜을 준수하려면 다음 두 가지 메서드를 구현해야 합니다.
makeUIViewController(context)- 이 메서드는 SwiftUI에 의해 기본UIViewController를 만듭니다. 여기에서UIViewController를 인스턴스화하고 초기 상태를 전달합니다.updateUIViewController(_, context)- 이 메서드는 상태가 변경될 때마다 SwiftUI에 의해 호출됩니다. 여기에서 기본UIViewController를 수정하여 상태 변경에 응답해야 합니다.
MapViewController을 만듭니다.
makeUIViewController(context) 함수 내에서 새 MapViewController를 인스턴스화하고 결과로 반환합니다. 이제 MapViewControllerBridge가 다음과 같이 표시됩니다.
MapViewControllerBridge
import GoogleMaps
import SwiftUI
struct MapViewControllerBridge: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> MapViewController {
return MapViewController()
}
func updateUIViewController(_ uiViewController: MapViewController, context: Context) {
}
}
ContentView에서 MapViewControllerBridge 사용
이제 MapViewControllerBridge에서 MapViewController의 인스턴스를 생성하므로 다음 단계는 ContentView 내에서 이 구조체를 사용하여 지도를 표시하는 것입니다.
- Xcode에서
ContentView파일을 엽니다.
ContentView은 SceneDelegate에서 인스턴스화되며 최상위 애플리케이션 뷰를 포함합니다. 지도가 이 파일 내에서 추가됩니다.
body속성 내에MapViewControllerBridge를 만듭니다.
이 파일의 body 속성 내에서 이미 ZStack이 제공 및 구현되어 있습니다. 현재 ZStack에는 이후 단계에서 사용할 수 있도록 드래그할 수 있는 드래그 가능한 도시 목록이 포함되어 있습니다. 지금은 ZStack 내에서 MapViewControllerBridge를 ZStack의 첫 번째 하위 뷰로 만들어 도시 보기 목록 뒤의 앱에 지도를 표시합니다. 이렇게 하면 ContentView 내의 body 속성 콘텐츠가 다음과 같이 표시됩니다.
콘텐츠 보기
var body: some View {
let scrollViewHeight: CGFloat = 80
GeometryReader { geometry in
ZStack(alignment: .top) {
// Map
MapViewControllerBridge()
// Cities List
CitiesList(markers: $markers) { (marker) in
guard self.selectedMarker != marker else { return }
self.selectedMarker = marker
self.zoomInCenter = false
self.expandList = false
} handleAction: {
self.expandList.toggle()
} // ...
}
}
}
- 이제 앱을 실행합니다. 이제 화면 하단에 드래그 가능한 도시 목록과 함께 지도 화면이 지도 화면에 표시됩니다.
7. 지도에 마커 추가하기
이전 단계에서는 도시 목록을 표시하는 상호작용 가능한 목록과 함께 지도를 추가했습니다. 이 섹션에서는 목록의 각 도시에 마커를 추가합니다.

상태 표시
ContentView현재markers 이것은 목록에 있는GMSMarker 선언되는 각 도시를cities 정적 속성입니다. 이 속성은 SwiftUI 속성 래퍼 상태로 주석 처리되어 SwiftUI에서 관리해야 함을 나타냅니다. 따라서 이 속성에서 마커가 추가되거나 삭제되는 등 변경사항이 감지되면 이 상태를 사용하는 뷰가 업데이트됩니다.
콘텐츠 보기
static let cities = [
City(name: "San Francisco", coordinate: CLLocationCoordinate2D(latitude: 37.7576, longitude: -122.4194)),
City(name: "Seattle", coordinate: CLLocationCoordinate2D(latitude: 47.6131742, longitude: -122.4824903)),
City(name: "Singapore", coordinate: CLLocationCoordinate2D(latitude: 1.3440852, longitude: 103.6836164)),
City(name: "Sydney", coordinate: CLLocationCoordinate2D(latitude: -33.8473552, longitude: 150.6511076)),
City(name: "Tokyo", coordinate: CLLocationCoordinate2D(latitude: 35.6684411, longitude: 139.6004407))
]
/// State for markers displayed on the map for each city in `cities`
@State var markers: [GMSMarker] = cities.map {
let marker = GMSMarker(position: $0.coordinate)
marker.title = $0.name
return marker
}
ContentView는 markers 속성을 사용하여 도시를 CitiesList 클래스에 전달하여 도시 목록을 렌더링합니다.
도시 목록
struct CitiesList: View {
@Binding var markers: [GMSMarker]
var body: some View {
GeometryReader { geometry in
VStack(spacing: 0) {
// ...
// List of Cities
List {
ForEach(0..<self.markers.count) { id in
let marker = self.markers[id]
Button(action: {
buttonAction(marker)
}) {
Text(marker.title ?? "")
}
}
}.frame(maxWidth: .infinity)
}
}
}
}
결합을 통해 State를 MapViewControllerBridge로 전달
markers 속성의 데이터를 표시하는 도시 목록 외에도 이 속성을 지도에 표시하는 데 사용할 수 있도록 이 속성을 MapViewControllerBridge 구조체에 전달합니다. 다음 안내를 따르세요.
MapViewControllerBridge내에서@Binding주석이 달린 새markers속성을 선언합니다.
MapViewControllerBridge
struct MapViewControllerBridge: : UIViewControllerRepresentable {
@Binding var markers: [GMSMarker]
// ...
}
MapViewControllerBridge에서markers속성을 사용하도록updateUIViewController(_, context)메서드를 업데이트합니다.
이전 단계에서 언급했듯이 updateUIViewController(_, context)는 상태가 변경될 때마다 SwiftUI에 의해 호출됩니다. 이 메서드 내에 지도를 업데이트하고자 하므로 markers에 마커를 표시합니다. 이렇게 하려면 각 마커의 map 속성을 업데이트해야 합니다. 이 단계를 완료하면 MapViewControllerBridge가 다음과 같이 표시됩니다.
import GoogleMaps
import SwiftUI
struct MapViewControllerBridge: UIViewControllerRepresentable {
@Binding var markers: [GMSMarker]
func makeUIViewController(context: Context) -> MapViewController {
return MapViewController()
}
func updateUIViewController(_ uiViewController: MapViewController, context: Context) {
// Update the map for each marker
markers.forEach { $0.map = uiViewController.map }
}
}
markers속성을ContentView에서MapViewControllerBridge로 전달
MapViewControllerBridge에 새 속성을 추가했으므로 이제 이 속성의 값을 MapViewControllerBridge의 초기화 프로그램에 전달해야 합니다. 따라서 앱을 빌드하려고 하면 컴파일되지 않는 것을 확인할 수 있습니다. 이 문제를 해결하려면 다음과 같이 MapViewControllerBridge가 만들어진 ContentView를 업데이트하고 markers 속성을 전달합니다.
struct ContentView: View {
// ...
var body: some View {
// ...
GeometryReader { geometry in
ZStack(alignment: .top) {
// Map
MapViewControllerBridge(markers: $markers)
// ...
}
}
}
}
접두사 $는 결합된 속성을 예상하므로 markers를 MapViewControllerBridge에 전달하는 데 사용되었습니다. $는 Swift 속성 래퍼와 함께 사용하기 위해 예약된 프리픽스입니다. 상태에 적용되면 Binding이 반환됩니다.
- 앱을 실행하여 지도에 표시된 마커를 확인하세요.
8. 선택한 도시에 애니메이션 적용
이전 단계에서는 SwiftUI 보기에서 다른 SwiftUI로 상태를 전달하여 지도에 마커를 추가했습니다. 이 단계에서는 상호작용 가능한 목록에서 탭한 도시/마커에 애니메이션을 적용합니다. 애니메이션을 실행하려면 변경 시 지도의 카메라 위치를 수정하여 상태에 변경사항이 반응해야 합니다. 지도 카메라 개념에 대해 자세히 알아보려면 카메라 및 뷰를 참고하세요.

선택한 도시에 지도 애니메이션 적용
선택한 도시로 지도에 애니메이션을 적용하는 방법은 다음과 같습니다.
MapViewControllerBridge에서 새 결합 정의해 주세요
ContentView에는 nil로 초기화되고 목록에서 도시가 선택될 때마다 업데이트되는 selectedMarker라는 State 속성이 있습니다. ContentView 내의 CitiesList 뷰 buttonAction에서 처리합니다.
콘텐츠 보기
CitiesList(markers: $markers) { (marker) in
guard self.selectedMarker != marker else { return }
self.selectedMarker = marker
// ...
}
selectedMarker가 변경될 때마다 MapViewControllerBridge는 선택한 마커에 지도를 애니메이션 처리할 수 있도록 상태 변경을 알려야 합니다. 따라서 MapViewControllerBridge 유형의 GMSMarker 내에서 새 결합을 정의하고 속성 이름을 selectedMarker로 지정합니다.
MapViewControllerBridge
struct MapViewControllerBridge: UIViewControllerRepresentable {
@Binding var selectedMarker: GMSMarker?
}
selectedMarker가 변경될 때마다 지도에 애니메이션을 적용하기 위해MapViewControllerBridge를 업데이트합니다.
새 결합이 선언되면 지도가 선택한 마커로 애니메이션 처리되도록 MapViewControllerBridge의 updateUIViewController_, context) 함수를 업데이트해야 합니다. 아래 코드를 복사하여 복사하세요.
struct MapViewControllerBridge: UIViewControllerRepresentable {
@Binding var selectedMarker: GMSMarker?
func updateUIViewController(_ uiViewController: MapViewController, context: Context) {
markers.forEach { $0.map = uiViewController.map }
selectedMarker?.map = uiViewController.map
animateToSelectedMarker(viewController: uiViewController)
}
private func animateToSelectedMarker(viewController: MapViewController) {
guard let selectedMarker = selectedMarker else {
return
}
let map = viewController.map
if map.selectedMarker != selectedMarker {
map.selectedMarker = selectedMarker
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
map.animate(toZoom: kGMSMinZoomLevel)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
map.animate(with: GMSCameraUpdate.setTarget(selectedMarker.position))
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
map.animate(toZoom: 12)
})
}
}
}
}
}
animateToSelectedMarker(viewController) 함수는 GMSMapView의 animate(with) 함수를 사용하여 일련의 지도 애니메이션 작업을 실행합니다.
ContentView의selectedMarker를MapViewControllerBridge에 전달
MapViewControllerBridge에서 새 결합을 선언했으면 ContentView를 업데이트하여 MapViewControllerBridge가 인스턴스화된 selectedMarker를 전달합니다.
콘텐츠 보기
struct ContentView: View {
// ...
var body: some View {
// ...
GeometryReader { geometry in
ZStack(alignment: .top) {
// Map
MapViewControllerBridge(markers: $markers, selectedMarker: $selectedMarker)
// ...
}
}
}
}
이제 이 단계를 완료하면 목록에서 새 도시가 선택될 때마다 지도에 애니메이션이 적용됩니다.
SwiftUI 뷰에 애니메이션을 적용하여 도시 강조
SwiftUI는 상태 전환을 위한 애니메이션 처리를 지원하므로 매우 쉽게 뷰를 애니메이션화할 수 있습니다. 이 기능을 보여주기 위해 지도 애니메이션이 완료된 후 선택한 도시에 보기를 집중시켜 애니메이션을 더 추가합니다. 이를 위해 다음 단계를 완료합니다.
MapViewControllerBridge클로저onAnimationEnded추가
SwiftUI 애니메이션은 이전에 추가한 지도 애니메이션 시퀀스 이후에 실행되므로 MapViewControllerBridge 내에서 onAnimationEnded이라는 새 클로저를 선언하고 animateToSelectedMarker(viewController) 내의 마지막 지도 애니메이션 후 0.5초 후에 이 클로저를 호출합니다. 메서드를 호출합니다.
MapViewControllerBridge
struct MapViewControllerBridge: UIViewControllerRepresentable {
var onAnimationEnded: () -> ()
private func animateToSelectedMarker(viewController: MapViewController) {
guard let selectedMarker = selectedMarker else {
return
}
let map = viewController.map
if map.selectedMarker != selectedMarker {
map.selectedMarker = selectedMarker
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
map.animate(toZoom: kGMSMinZoomLevel)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
map.animate(with: GMSCameraUpdate.setTarget(selectedMarker.position))
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
map.animate(toZoom: 12)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
// Invoke onAnimationEnded() once the animation sequence completes
onAnimationEnded()
})
})
}
}
}
}
}
MapViewControllerBridge에onAnimationEnded을 구현합니다.
MapViewControllerBridge 내에서 ContentView를 인스턴스화하는 onAnimationEnded 클로저를 구현합니다. 다음 코드를 복사하여 붙여넣고 zoomInCenter라는 새 상태를 추가합니다. 또한 clipShape를 사용하여 뷰를 수정하고 잘린 도형의 지름이 zoomInCenter 값에 따라 달라집니다.
콘텐츠 보기
struct ContentView: View {
@State var zoomInCenter: Bool = false
// ...
var body: some View {
// ...
GeometryReader { geometry in
ZStack(alignment: .top) {
// Map
let diameter = zoomInCenter ? geometry.size.width : (geometry.size.height * 2)
MapViewControllerBridge(markers: $markers, selectedMarker: $selectedMarker, onAnimationEnded: {
self.zoomInCenter = true
})
.clipShape(
Circle()
.size(
width: diameter,
height: diameter
)
.offset(
CGPoint(
x: (geometry.size.width - diameter) / 2,
y: (geometry.size.height - diameter) / 2
)
)
)
.animation(.easeIn)
.background(Color(red: 254.0/255.0, green: 1, blue: 220.0/255.0))
}
}
}
}
- 앱을 실행하여 애니메이션을 확인하세요.
9. SwiftUI 이벤트 보내기
이 단계에서는 GMSMapView에서 내보낸 이벤트를 수신 대기하고 이 이벤트를 SwiftUI로 전송합니다. 특히 대리자가 지도뷰에 설정하고 카메라 이동 이벤트를 수신 대기하여 도시의 초점이 맞춰지고 지도 카메라가 동작에서 나오면 지도뷰에서 초점이 해제되어 지도를 더 많이 볼 수 있습니다.
SwiftUI 코디네이터 사용
GMSMapView는 카메라 위치 변경이나 마커를 탭할 때와 같은 이벤트를 내보냅니다. 이러한 이벤트를 수신 대기하는 메커니즘은 GMSMapViewDelegate 프로토콜을 통해 이루어집니다. SwiftUI는 UIKit 뷰 컨트롤러의 대리자 역할을 하는 데 사용되는 코디네이터의 개념을 도입합니다. 따라서 SwiftUI 환경에서는 코디네이터가 GMSMapViewDelegate 프로토콜을 준수해야 합니다. 이렇게 하려면 다음 단계를 완료해야 합니다.
MapViewControllerBridge내에MapViewCoordinator라는 코디네이터를 만듭니다.
MapViewControllerBridge 클래스 내에 중첩 클래스를 만들고 이름을 MapViewCoordinator로 지정합니다. 이 클래스는 GMSMapViewDelegate를 준수해야 하며 MapViewControllerBridge를 속성으로 선언해야 합니다.
MapViewControllerBridge
struct MapViewControllerBridge: UIViewControllerRepresentable {
// ...
final class MapViewCoordinator: NSObject, GMSMapViewDelegate {
var mapViewControllerBridge: MapViewControllerBridge
init(_ mapViewControllerBridge: MapViewControllerBridge) {
self.mapViewControllerBridge = mapViewControllerBridge
}
}
}
MapViewControllerBridge에makeCoordinator()을 구현합니다.
그런 다음 MapViewControllerBridge 내에 makeCoordinator() 메서드를 구현하고 이전 단계에서 만든 MapViewCoodinator 인스턴스를 반환합니다.
MapViewControllerBridge
struct MapViewControllerBridge: UIViewControllerRepresentable {
// ...
func makeCoordinator() -> MapViewCoordinator {
return MapViewCoordinator(self)
}
}
MapViewCoordinator를 지도뷰의 대리자로 설정
맞춤 코디네이터를 만든 후 다음 단계는 코디네이터를 뷰 컨트롤러의 지도뷰의 대리자로 설정하는 것입니다. 이렇게 하려면 makeUIViewController(context)에서 뷰 컨트롤러 초기화를 업데이트합니다. 이전 단계에서 만든 코디네이터는 Context 객체에서 액세스할 수 있습니다.
MapViewControllerBridge
struct MapViewControllerBridge: UIViewControllerRepresentable {
// ...
func makeUIViewController(context: Context) -> MapViewController {
let uiViewController = MapViewController()
uiViewController.map.delegate = context.coordinator
return uiViewController
}
- 카메라가 움직이는 이벤트를 전파할 수 있도록
MapViewControllerBridge에 클로저를 추가합니다.
카메라 이동으로 뷰를 업데이트하는 것이 목표이므로 MapViewControllerBridge 내에서 mapViewWillMove라는 부울을 허용하는 새 닫는 속성을 선언하고 MapViewCoordinator 내의 대리자 메서드 mapView(_, willMove)에서 이 클로저를 호출합니다. SwiftUI 뷰가 동작 관련 카메라 이동 이벤트에만 반응할 수 있도록 gesture 값을 클로저에 전달합니다.
MapViewControllerBridge
struct MapViewControllerBridge: UIViewControllerRepresentable {
var mapViewWillMove: (Bool) -> ()
//...
final class MapViewCoordinator: NSObject, GMSMapViewDelegate {
// ...
func mapView(_ mapView: GMSMapView, willMove gesture: Bool) {
self.mapViewControllerBridge.mapViewWillMove(gesture)
}
}
}
mapWillMove값을 전달하려면 ContentView 업데이트
MapViewControllerBridge에 새 클로저가 선언되었으므로 ContentView를 업데이트하여 이 새 클로저의 값을 전달합니다. 이 클로저 내에서 이동 이벤트가 동작과 관련된 경우 상태 zoomInCenter를 false로 전환합니다. 그러면 동작으로 지도가 이동할 때 지도가 전체 보기로 다시 표시됩니다.
콘텐츠 보기
struct ContentView: View {
@State var zoomInCenter: Bool = false
// ...
var body: some View {
// ...
GeometryReader { geometry in
ZStack(alignment: .top) {
// Map
let diameter = zoomInCenter ? geometry.size.width : (geometry.size.height * 2)
MapViewControllerBridge(markers: $markers, selectedMarker: $selectedMarker, onAnimationEnded: {
self.zoomInCenter = true
}, mapViewWillMove: { (isGesture) in
guard isGesture else { return }
self.zoomInCenter = false
})
// ...
}
}
}
}
- 앱을 실행하여 새 변경사항을 확인하세요.
10. 축하합니다
여기까지 오신 여러분을 축하합니다. 많은 내용을 살펴봤습니다. 이제 배운 내용을 바탕으로 iOS용 Maps SDK를 사용하여 SwiftUI 앱을 직접 빌드할 수 있기를 바랍니다.
학습한 내용
- SwiftUI와 UIKit의 차이점
- UIViewControllerRepresentable을 사용하여 SwiftUI와 UIKit를 연결하는 방법
- 지도뷰를 변경하는 방법구/군/시 및바인딩
- 코디네이터를 사용하여 지도뷰에서 SwiftUI로 이벤트를 전송하는 방법
다음 단계
- iOS용 Maps SDK - iOS용 Maps SDK 공식 문서
- iOS용 Places SDK - 주변의 지역 비즈니스 및 관심 장소를 찾습니다.
- maps-sdk-for-ios-samples - iOS용 Maps SDK 내의 모든 기능을 보여주는 GitHub의 샘플 코드입니다.
- SwiftUI - SwiftUI에 관한 Apple의 공식 문서
- 아래 질문에 답하여 Google에서 가장 유용한 콘텐츠를 만들 수 있도록 도와주세요.
다른 Codelab에서 어떤 내용을 다뤘으면 하시나요?
원하는 Codelab이 위에 나와 있지 않나요? 여기에서 새로운 문제로 요청하기