searchText
를 만들어서 해당 텍스트를 포함하는 resorts
만 필터를 거쳐 보여주도록 설정했다.
ResortView의 SkiDetailsView, ResortDetailsView를 디바이스의 가로, 세로, 텍스트 크기에 따라 화면의 요소를 동적으로 나타내도록 설정했다.
@Environment(\.horizontalSizeClass) var horizontalSizeClass
@Environment(\.dynamicTypeSize) var dynamicTypeSize
// ...
if horizontalSizeClass == .compact && dynamicTypeSize > .large {
VStack(spacing: 10) {
SkiDetailsView(resort: resort)
}
VStack(spacing: 10) {
ResortDetailsView(resort: resort)
}
} else {
SkiDetailsView(resort: resort)
ResortDetailsView(resort: resort)
}
그리고 해당 글자를 xxxLarge까지만 크게 볼 수 있도록 제한도 했다.
.dynamicTypeSize(...DynamicTypeSize.xxxLarge)
💡 Size 참고:
시설을 icon으로 나타내고 이를 클릭하면 alert으로 자세한 정보를 볼 수 있도록 설정했다.
❗️ 참고로 위 커밋에서 구조체 Facility를 Identifiable로 설정하지 않아서 'Failed to produce diagnostic for expression; please submit a bug report' 에러를 겪었다. 아래 커밋은 디버깅 완료한 커밋이다.
커밋 링크
동적으로 변하는 좋아요 리스트를 만들고자 @Observable인 class Favorite을 만들었다. 강의처럼 데이터를 불러오거나 저장하는 함수는 비워뒀다.
import SwiftUI
@Observable
class Favorites {
private var resorts: Set<String>
private let key = "Favorites"
init() {
// load favorite resorts
resorts = []
}
func contains(_ resort: Resort) -> Bool {
if resorts.contains(resort.id) {
return true
} else {
return false
}
}
func add(_ resort: Resort) {
resorts.insert(resort.id)
save()
}
func remove(_ resort: Resort) {
resorts.remove(resort.id)
save()
}
func save() {
// save favorite resorts
}
}
그리고 이 좋아요를 나타낼 favorites를 ContentView에서 변수로 설정하고, 버튼을 나타낼 ResortView에서 Environment로 불렀다.
@State private var favorites = Favorites()
// ... NavigationSplitView
.environment(favorites)
@Environment(Favorites.self) var favorites
❗️ preview가 작동하는 것을 보려면 아래 코드처럼 .environment를 설정해야 한다.
#Preview {
ResortView(resort: .example)
.environment(Favorites())
}
그리고 마지막으로 ResortView에서는 toolbar의 버튼으로, ContentView에서는 목록 옆의 하트로 나타냈다. 강의에서는 VStack 안의 "Remove from Favorites" 혹은 "Add to Favorites" 버튼을 누르도록 설정했는데, 접근성을 높이고 아이콘을 이용해 직관적으로 보여주고자 toolbar에 heart.fill 혹은 heart로 기본 아이콘으로 나타냈다.
.toolbar {
Button("Favorite", systemImage: favorites.contains(resort) ? "heart.fill" : "heart") {
if favorites.contains(resort) {
favorites.remove(resort)
} else {
favorites.add(resort)
}
}
}
if favorites.contains(resort) {
Spacer()
Image(systemName: "heart.fill")
.foregroundColor(.secondary)
}