iOS 13.*에 추가된 SwiftUI 연습 네비게이션과 리스트 추가 입니다 #2

in #kr5 years ago (edited)

두번째로 리스트와 네비게이션 사용하기 입니다.
아래의 예제가 상당히 재미있습니다.

기존에 스토리보드를 많이 사용하던 개발자라면 한번 테스트해 보세요.
아래의 링크에서 샘플을 받아서 StartingPoint폴더에 있는 프로젝트를 오픈 해야 합니다.

https://developer.apple.com/tutorials/swiftui/building-lists-and-navigation

새로운 파일들이 많이 추가되어 있다. 새로 제공된 시작 프로젝트를 오픈 합니다.

Section 2: Row View 생성하기

스크린샷 2019-10-07 오후 3.08.41.png

각 랜드마크의 상세를 표시하는 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()
}
}

실행하면 아직은 상세화면만 출력됩니다.

스크린샷 2019-10-07 오전 11.52.40.png

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()
    }
}

실행하면 다음과 같이 네비게이션이 되고 상세 화면으로 전환할 수 있습니다.

스크린샷 2019-10-07 오후 3.00.29.png

스크린샷 2019-10-07 오후 3.00.36.png

Sort:  
  • 스팀 코인판 커뮤니티를 이용해주셔서 감사합니다.
  • 2019년 10월 15일부터는 스팀코인판에서 작성한 글만 SCT 토큰을 보상받을 수 있습니다
  • 스팀 코인판 이외의 곳에서 작성된 글은 SCT 보상에서 제외되니 주의 바랍니다.