두번째로 리스트와 네비게이션 사용하기 입니다.
아래의 예제가 상당히 재미있습니다.
기존에 스토리보드를 많이 사용하던 개발자라면 한번 테스트해 보세요.
아래의 링크에서 샘플을 받아서 StartingPoint폴더에 있는 프로젝트를 오픈 해야 합니다.
https://developer.apple.com/tutorials/swiftui/building-lists-and-navigation
새로운 파일들이 많이 추가되어 있다. 새로 제공된 시작 프로젝트를 오픈 합니다.
Section 2: Row View 생성하기
각 랜드마크의 상세를 표시하는 row를 생성합니다.
SwiftUI템플릿을 선택해서 LandmarkRow.swift를 추가합니다.
아래와 같이 입력합니다.
import SwiftUI
struct LandmarkRow: View {
var body: some View {
HStack {
landmark.image
.resizable()
.frame(width: 50, height: 50)
Text(landmark.name)
}
}
}
struct LandmarkRow_Previews: PreviewProvider {
static var previews: some View {
LandmarkRow(landmark: landmarkData[0])
}
}
Section 3: Row Preview를 커스터마이징하기
Xcode의 canvas는 자동으로 현재 에디터의 어떤 형식도 감지하고 표시합니다.
Preview provider는 하나 또는 그 이상의 뷰들을 리턴합니다. 사이즈와 디바이스로 셋팅된 옵션과 함께 합니다.
import SwiftUI
struct LandmarkRow: View {
var body: some View {
HStack {
landmark.image
.resizable()
.frame(width: 50, height: 50)
Text(landmark.name)
}
}
}
struct LandmarkRow_Previews: PreviewProvider {
static var previews: some View {
Group {
LandmarkRow(landmark: landmarkData[0])
.previewLayout(.fixed(width:300, height: 70))
LandmarkRow(landmark: landmarkData[1])
.previewLayout(.fixed(width:300, height: 70))
}
.previewLayout(.fixed(width:300, height: 70))
}
}
LandmarkList라는 SwiftUI템플릿을 사용한 파일을 추가합니다. 아래와 같이 수정합니다.
import SwiftUI
struct LandmarkList: View {
var body: some View {
List {
LandmarkRow(landmarK: landmarkData[0])
LandmarkRow(landmarK: landmarkData[1])
}
}
}
struct LandmarkList_Previews: PreviewProvider {
static var previews: some View {
LandmarkList()
}
}
Section 5: 동적인 리스트 만들기
컬렉션에서 직접 로우를 생성할 수 있습니다.
아래와 같이 LandmarkList를 수정합니다.
import SwiftUI
struct LandmarkList: View {
var body: some View {
List(landmarkData, id: .id) { landmark in
LandmarkRow(landmark: landmark)
}
}
}
struct LandmarkList_Previews: PreviewProvider {
static var previews: some View {
LandmarkList()
}
}
Models폴더에 있는 Landmark.swift를 살펴봅니다.
아래와 같이 id:을 삭제하고 코드를 수정합니다.
import SwiftUI
struct LandmarkList: View {
var body: some View {
List(landmarkData) { landmark in
LandmarkRow(landmark: landmark)
}
}
}
struct LandmarkList_Previews: PreviewProvider {
static var previews: some View {
LandmarkList()
}
}
실행하면 아직은 상세화면만 출력됩니다.
Section 6: 리스트와 상세 사이에 네비게이션
import SwiftUI
struct LandmarkList: View {
var body: some View {
NavigationView {
List(landmarkData) { landmark in
NavigationLink(destination: LandmarkDetail()) {
LandmarkRow(landmark: landmark)
}
}
.navigationBarTitle(Text("Landmarks"))
}
}
}
struct LandmarkList_Previews: PreviewProvider {
static var previews: some View {
LandmarkList()
}
}
Section 7: Child View로 데이터 전달하기
LandmarkDetail 뷰는 상세 정보가 하드 코딩되어 있습니다.
데이터를 넘겨받도록 합니다.
LandMarkDetail을 아래와 같이 수정합니다.
import SwiftUI
struct LandmarkDetail: View {
var landmark: Landmark
var body: some View {
VStack {
MapView(coordinate: landmark.locationCoordinate)
.frame(height: 300)
CircleImage(image: landmark.image)
.offset(x: 0, y: -130)
.padding(.bottom, -130)
VStack(alignment: .leading) {
Text(landmark.name)
.font(.title)
HStack(alignment: .top) {
Text(landmark.park)
.font(.subheadline)
Spacer()
Text(landmark.state)
.font(.subheadline)
}
}
.padding()
Spacer()
}
.navigationBarTitle(Text(verbatim: landmark.name), displayMode: .inline)
}
}
struct LandmarkDetail_Previews: PreviewProvider {
static var previews: some View {
LandmarkDetail(landmark: landmarkData[0])
}
}
LandmarkRow는 아래와 같이 수정합니다.
import SwiftUI
struct LandmarkRow: View {
var landmark: Landmark
var body: some View {
HStack {
landmark.image
.resizable()
.frame(width: 50, height: 50)
Text(verbatim: landmark.name)
Spacer()
}
}
}
struct LandmarkRow_Previews: PreviewProvider {
static var previews: some View {
Group {
LandmarkRow(landmark: landmarkData[0])
LandmarkRow(landmark: landmarkData[1])
}
.previewLayout(.fixed(width: 300, height: 70))
}
}
Models폴더에 있는 Landmark는 프로토콜만 추가합니다.
import SwiftUI
import CoreLocation
struct Landmark: Hashable, Codable, Identifiable {
var id: Int
var name: String
fileprivate var imageName: String
fileprivate var coordinates: Coordinates
var state: String
var park: String
var category: Category
LandmarkList는 아래와 같이 수정합니다.
import SwiftUI
struct LandmarkList: View {
var body: some View {
NavigationView {
List(landmarkData) { landmark in
NavigationLink(destination: LandmarkDetail(landmark: landmark)) {
LandmarkRow(landmark: landmark)
}
}
.navigationBarTitle(Text("Landmarks"))
}
}
}
struct LandmarkList_Previews: PreviewProvider {
static var previews: some View {
ForEach(["iPhone SE", "iPhone XS Max"], id: .self) { deviceName in
LandmarkList()
.previewDevice(PreviewDevice(rawValue: deviceName))
.previewDisplayName(deviceName)
}
}
}
진입점 역할을 수행하는 코드는 SceneDelegate에 있습니다.
import UIKit
import SwiftUI
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
// Use a UIHostingController as window root view controller
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: LandmarkList())
self.window = window
window.makeKeyAndVisible()
}
}
실행하면 다음과 같이 네비게이션이 되고 상세 화면으로 전환할 수 있습니다.