2019년 10월 7일 월요일

iOS 13.*에 추가된 SwiftUI 연습 사용자 입력 추가하기 #3

세번째 데모는 입력 처리 추가하기 입니다. 아래의 링크에서 StartingPoing폴더에 있는 프로젝트를 오픈하면 됩니다.
사용자가 랜드마크를 보고 별표 표시를 하는 경우
스크린샷 2019-10-07 오후 4.18.52.png
StartingPoing폴더에 있는 시작 프로젝트를 오픈 합니다.
LandmarkRow파일에서 아래와 같이 수정합니다.
import SwiftUI
struct LandmarkRow: View {
var landmark: Landmark
var body: some View {
    HStack {
        landmark.image
            .resizable()
            .frame(width: 50, height: 50)
        Text(landmark.name)
        Spacer()
        
        if landmark.isFavorite {
            Image(systemName: "star.fill")
                .imageScale(.medium)
        }
    }
}
}
Section 2: List View를 필터링하기
사용자가 좋아하는 것만 필터링할 수 있습니다.
View에 상태를 추가하기 위해 @State속성을 사용할 수 있습니다.
LandmarkList를 아래와 같이 수정합니다.
import SwiftUI
struct LandmarkList: View {
@State var showFavoritesOnly = false

var body: some View {
    NavigationView {
        List(landmarkData) { landmark in
            if !self.showFavoritesOnly ||
                landmark.isFavorite {
                NavigationLink(destination: LandmarkDetail(landmark: landmark)) {
                    LandmarkRow(landmark: landmark)
                }
            }
        }
        .navigationBarTitle(Text("Landmarks"))
    }
}
}
Section 3: 상태를 토글하기 위해 컨트롤을 추가합니다.
유저가 리스트 필터링을 컨트롤하도록, 컨트롤을 추가합니다.
LandmarkList를 수정합니다.
import SwiftUI
struct LandmarkList: View {
@State var showFavoritesOnly = true

var body: some View {
    NavigationView {
        List {
            ForEach(landmarkData) { landmark in
                if !self.showFavoritesOnly ||
                    landmark.isFavorite {
                    NavigationLink(destination: LandmarkDetail(landmark: landmark)) {
                        LandmarkRow(landmark: landmark)
                    }
                }
            }
        }
        .navigationBarTitle(Text("Landmarks"))
    }
}
}
다시 아래와 같이 추가합니다.
import SwiftUI
struct LandmarkList: View {
@State var showFavoritesOnly = true

var body: some View {
    NavigationView {
        List {
            Toggle(isOn: $showFavoritesOnly) {
                Text("Favorites only")
            }
            
            ForEach(landmarkData) { landmark in
                if !self.showFavoritesOnly ||
                    landmark.isFavorite {
                    NavigationLink(destination: LandmarkDetail(landmark: landmark)) {
                        LandmarkRow(landmark: landmark)
                    }
                }
            }
        }
        .navigationBarTitle(Text("Landmarks"))
    }
}
}
스크린샷 2019-10-07 오후 4.11.38.png
Section 4: Storage를 위해 Observable Object를 사용한다.
좋아하는 랜드마크를 컨트롤하도록 준비하기 위해 먼저 observable object로
랜드마크 데이터를 저장해야 합니다.
observable object는 storage로 부터 SwiftUI환경으로 뷰를 바운드할 수 있습니다.
SwiftUI는 뷰에 영향을 주는 observable object에 대한 변경을 감시하고,
그리고 변경후에 뷰의 올바른 버전을 표시합니다.
Models폴더에 UserData.swift파일을 추가해서 아래와 같이 코딩 합니다.
import SwiftUI
import Combine
final class UserData : ObservableObject {
@Published var showFavoritesOnly = false
@Published var landmarks = landmarkData
}
Section 5: 뷰에 Model Object을 붙이기
UserData 오브젝트를 생성한 후에 앱의 데이터 저장으로 뷰를 적용하도록 업데이트합니다.
LandmarkList를 수정합니다.
import SwiftUI
struct LandmarkList: View {
//다음과 같이 수정한다.
@EnvironmentObject var userData: UserData

var body: some View {
    NavigationView {
        List {
            Toggle(isOn: $userData.showFavoritesOnly) {
                Text("Favorites only")
            }
            
            ForEach(userData.landmarkData) { landmark in
                if !self.userData.showFavoritesOnly ||
                    landmark.isFavorite {
                    NavigationLink(destination: LandmarkDetail(landmark: landmark)) {
                        LandmarkRow(landmark: landmark)
                    }
                }
            }
        }
        .navigationBarTitle(Text("Landmarks"))
    }
}
}
struct LandmarkList_Previews: PreviewProvider {
static var previews: some View {
LandmarkList()
.environmentObject(UserData())
}
}
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()
                .environmentObject(UserData())
        )
        self.window = window
        window.makeKeyAndVisible()
    }
}
LandmarkDetail을 수정합니다.
import SwiftUI
struct LandmarkDetail: View {
@EnvironmentObject var userData: UserData
var landmark: Landmark
var landmarkIndex: Int {
    userDAta.landmarks.firstIndex(
        where: { $0.id == landmark.id })!
}

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])
.environmentObject(UserData())
}
}
Section 6: 각 랜드마크에 대한 Favorite 버튼을 생성합니다.
LandmarkDetail을 수정합니다.
import SwiftUI
struct LandmarkDetail: View {
@EnvironmentObject var userData: UserData
var landmark: Landmark
var landmarkIndex: Int {
    userData.landmarks.firstIndex(where: { $0.id == landmark.id })!
}

var body: some View {
    VStack {
        MapView(coordinate: landmark.locationCoordinate)
            .edgesIgnoringSafeArea(.top)
            .frame(height: 300)
        
        CircleImage(image: landmark.image)
            .offset(x: 0, y: -130)
            .padding(.bottom, -130)
        
        VStack(alignment: .leading) {
            HStack {
                Text(verbatim: landmark.name)
                    .font(.title)
                
                Button(action: {
                    self.userData.landmarks[self.landmarkIndex]
                        .isFavorite.toggle()
                }) {
                    if self.userData.landmarks[self.landmarkIndex]
                        .isFavorite {
                        Image(systemName: "star.fill")
                            .foregroundColor(Color.yellow)
                    } else {
                        Image(systemName: "star")
                            .foregroundColor(Color.gray)
                    }
                }
            }
            
            HStack(alignment: .top) {
                Text(verbatim: landmark.park)
                    .font(.subheadline)
                Spacer()
                Text(verbatim: landmark.state)
                    .font(.subheadline)
            }
        }
        .padding()
        
        Spacer()
    }
}
}
struct LandmarkDetail_Preview: PreviewProvider {
static var previews: some View {
let userData = UserData()
return LandmarkDetail(landmark: userData.landmarks[0])
.environmentObject(userData)
}
}
실행하면 다음과 같습니다.

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

댓글 없음:

댓글 쓰기

참고: 블로그의 회원만 댓글을 작성할 수 있습니다.

5월 14일 새벽에 chatGPT 4o가 발표되었습니다. 옵티마이즈, 옴니라는 의미인데 실시간 통역, 다자간 회의, 멀티모달 기능의 강화등이 보이네요.

  초격차로 OpenAI진영이 다시 앞서가는 모양을 보여주고 있습니다. 저도 새벽에 일어나자 마자 올라온 영상들과 글을 정리하고 있습니다. ㅎㅎ 영화 HER의 사진이 새벽에 많이 올라왔었는데 저도 안본 영화입니다. 주말에 한번 봐야 할 것 같습니다....