지난 작업에서는 저장된 데이터 베이스를 활용하여 LandmarkList.swift를 구현하였다.
이번 튜토리얼에서는 구성한 list view를 눌렀을 때 세부 정보를 보여주는 LandmarkDetail.swift를 작성하고, 리스트를 눌렀을 때 화면을 연결하는 Navigation에 대한 내용을 다루고 있다.
우선, LandmarkDetail.swift 파일을 새로 생성하고 기존에 ContentView에 있는 내용을 복사-붙여넣기 한다. 그리고 ContentView에는 LandmarkList()를 넣어준다.
이제 우리의 앱은 초기 화면인 LandmarkList와 각 리스트에 있는 랜드마크를 눌렀을 때 각 랜드마크에 해당하는 디테일한 정보를 볼 수 있는 LandmarkDetail의 두 가지 화면으로 구성되게 된다.
// ContentView.swift
struct ContentView: View {
var body: some View {
LandmarkList()
}
}
// LandmarkDetail.swift
struct LandmarkDetail: View {
var body: some View {
VStack {
MapView()
.ignoresSafeArea(edges: .top)
.frame(height: 300)
CircleImage()
.offset(y: -130)
.padding(.bottom, -130)
VStack(alignment: .leading) {
Text("Turtle Rock")
.font(.title)
.foregroundColor(.primary)
HStack {
Text("Joshua Tree National Park")
Spacer()
Text("California")
}
.font(.subheadline)
.foregroundColor(.secondary)
Divider()
Text("About Turtle Rock")
.font(.title2)
Text("Descriptive text goes here.")
}
.padding()
Spacer()
}
}
}
이제 LandmarkList와 LandmarkDetail을 연결해야 한다. 연결은 NavigationView와 NavigationLink를 사용하여 가능하다. 들어가기 전에 사담을 하나 달자면, 이전에 iOS 앱을 만들 때 스토리보드 기반의 navigation이 오히려 더 어렵게 느껴졌었는데 SwiftUI에서는 굉장히 편하게 할 수 있었다.
LandmarkList로 가서 NavigationView와 NavigationLink를 추가한다.
struct LandmarkList: View {
var body: some View {
NavigationView {
List(landmarks) { landmark in
NavigationLink(destination: LandmarkDetail()) {
LandmarkRow(landmark: landmark)
}
}
.navigationTitle("Landmarks")
}
}
}
NavigationView를 통해 내부에 있는 view에서 화면 간 이동을 할 수 있게 되고, NavigationLink를 통해서 도착 지점(destination)으로 이동할 수 있다. 이 코드에서는 List에 있는 LandmarkRow를 누를 경우 LandmarkDetail로 이동할 수 있다.
여기까지 튜토리얼을 진행할 경우 다른 landmark를 누르더라도 turtlerock의 정보가 저장된 detail 화면으로 이동하게 된다. 이제 한 가지 작업을 더 해줘야 한다. 바로 landmark 정보를 LandmarkDetail로 넘겨 화면을 표시할 수 있도록 하는 작업이다.
그를 위해 우선 LandmarkDetail을 구성하고 있는 view들을 수정해야 한다. 현재는 각 view들에서 표시되는 정보가 하드코딩되어 있기 때문에 이 부분을 수정해주어야 한다.
우선, 사진을 표현하는 CircleImage부터 수정해보도록 하겠다. 넘겨받은 이미지를 사용하기 위해 구조체 내부에 image를 선언하여 사용하도록 하였다. 이 때, Preview를 표시하기 위해서는 image를 넘겨주어야 한다. 이 때, 빌드 에러가 발생할 수 있다. 왜냐하면 LandmarkDetail에서 사용되는 CircleImage에 대한 인자를 전달받지 못하기 때문이다. 이 부분은 일단 무시하고 넘어가도록 한다.
// CircleImage.swift
import SwiftUI
struct CircleImage: View {
var image: Image
var body: some View {
image
.clipShape(Circle())
.overlay(Circle().stroke(Color.white, lineWidth: 4))
.shadow(radius: 7)
}
}
struct CircleImage_Previews: PreviewProvider {
static var previews: some View {
CircleImage(image: Image("turtlerock"))
}
}
그러고 나서는 이제 위치 정보를 표현하는 MapView를 수정해야 한다. MapView에서는 저장된 위-경도 좌표를 받아서 사용할 수 있도록 내부에 coordinate를 선언하고, 표시하고자 하는 부분을 지도에 나타내기 위한 setRegion 함수를 선언해준다.
// MapView.swift
import SwiftUI
import MapKit
struct MapView: View {
var coordinate: CLLocationCoordinate2D
@State private var region = MKCoordinateRegion()
var body: some View {
Map(coordinateRegion: $region)
.onAppear {
setRegion(coordinate)
}
}
private func setRegion(_ coordinate: CLLocationCoordinate2D) {
region = MKCoordinateRegion(
center: coordinate,
span: MKCoordinateSpan(latitudeDelta: 0.2, longitudeDelta: 0.2)
)
}
}
coordinate는 전달 받아서 사용하고 전달 받은 coordinate를 사용하여 지역을 설정한다. 이 때, onAppear modifier를 사용하여 렌더링 되는 순간 지역을 설정하도록 코드를 수정한다.
이제 남은 작업은 랜드마크의 위치, 정보 등을 받아서 사용할 수 있도록, CircleImage와 MapView에서 인자를 받지 않아 빌드 에러가 나는 부분을 해결해주면 된다.
// LandmarkDetail.swift
struct LandmarkDetail: View {
var landmark: Landmark
var body: some View {
ScrollView {
MapView(coordinate: landmark.locationCoordinate)
.ignoresSafeArea(edges: .top)
.frame(height: 300)
CircleImage(image: landmark.image)
.offset(y: -130)
.padding(.bottom, -130)
VStack(alignment: .leading) {
Text(landmark.name)
.font(.title)
.foregroundColor(.primary)
HStack {
Text(landmark.park)
Spacer()
Text(landmark.state)
}
.font(.subheadline)
.foregroundColor(.secondary)
Divider()
Text("About \(landmark.name)")
.font(.title2)
Text(landmark.description)
}
.padding()
}
.navigationTitle(landmark.name)
.navigationBarTitleDisplayMode(.inline)
}
}
랜드마크를 받아서 사용할 수 있도록 landmark를 선언해주었고, 각 정보들을 받아온 데이터를 사용하여 표현할 수 있도록 수정하였다. 그리고 랜드마크의 세부 정보가 길어 화면이 잘리게 되므로 VStack을 ScrollView로 바꾸어 스크롤을 통해 모든 내용을 확인할 수 있도록 수정한다. 이 과정에서 Spacer()를 제거한다.

이 과정을 거치게 되면 이런 화면을 얻을 수 있다. 리스트에서 랜드마크를 누르게 되면 랜드마크의 세부정보로 이동할 수 있게 된다.
이번 튜토리얼에서 주로 다루는 리스트 생성과 네비게이션을 하는 부분을 다 다루었다. 튜토리얼을 따라하며 느낀 점은 스토리보드 기반의 개발보다 훨씬 편리하다는 점 정도가 있겠다.
'개발 > iOS' 카테고리의 다른 글
[SwiftUI Essentials] Handling User Input - 2 (0) | 2021.07.24 |
---|---|
[SwiftUI Essentials] Handling User Input - 1 (0) | 2021.07.21 |
[SwiftUI Essentials] Building Lists and Navigation - 3 (0) | 2021.07.18 |
[SwiftUI Essentials] Building Lists and Navigation - 2 (0) | 2021.07.14 |
[SwiftUI Essentials] Building Lists and Navigation - 1 (0) | 2021.07.11 |