Using a List as a custom animated menu | SwiftUI Map App #4
구현 목표
구현 태스크
- 리스트 뷰 UI 구현
- 리스트 뷰 애니메이션 구현
- 선택 지역 이동 로직 구현
핵심 코드
import Foundation
import MapKit
struct LocationModel: Identifiable, Equatable {
let name: String
let cityName: String
let coordinates: CLLocationCoordinate2D
let description: String
let imageNames: [String]
let link: String
var id: String {
name + cityName
}
static func == (lhs: LocationModel, rhs: LocationModel) -> Bool {
lhs.id == rhs.id
}
}
- 리스트 뷰를 그릴 때
ForEach
에 넣어줄 데이터 구별을 위한 Identifiable
프로토콜을 따르는 id
Equatable
프로토콜을 따름으로써 이후 animated
의 value
로 해당 데이터를 넘겨줄 수 있음
extension LocationsView {
private var header: some View {
VStack {
Button {
viewModel.toggleLocationsList()
} label: {
Text(viewModel.mapLocation.name + ", " + viewModel.mapLocation.cityName)
.font(.title2)
.fontWeight(.black)
.foregroundColor(.primary)
.frame(maxWidth: .infinity, maxHeight: 55)
.animation(.none, value: viewModel.mapLocation)
.overlay(alignment: .leading) {
Image(systemName: "arrow.down")
.font(.headline)
.foregroundColor(.primary)
.padding()
.rotationEffect(Angle(degrees: viewModel.showLocationList ? 180 : 0))
}
}
if viewModel.showLocationList {
LocationsListView()
}
}
.background(.thinMaterial)
.cornerRadius(10)
.shadow(color: Color.black.opacity(0.3), radius: 20, x: 0, y: 15)
}
}
- 익스텐션으로 별도로 관리하는 로케이션 뷰의 헤더
- 해당 타이틀 헤더를 클릭함으로써 뷰 모델이 가지고 있는
showLocationList
불리언 변수 값이 변경
- 해당 값을 통해
LocationListView
를 표시할지 결정
import SwiftUI
struct LocationsListView: View {
@EnvironmentObject private var viewModel: LocationsViewModel
var body: some View {
List {
ForEach(viewModel.locations) { location in
Button {
viewModel.showNextLocation(location: location)
} label: {
listRowView(location: location)
}
.padding(.vertical, 4)
.listRowBackground(Color.clear)
}
}
.listStyle(.plain)
}
}
- 뷰 모델이 가지고 있는 로케이션 데이터 내 이미지를 리스트 UI를 통해 표현
showNextLocation
함수는 리스트 내 셀 클릭 시 현재 선택된 로케이션을 변경
Button
의 액션 및 라벨을 통해 위의 UI 및 함수를 연결
func toggleLocationsList() {
withAnimation(.easeInOut) {
showLocationList.toggle()
}
}
- 뷰 모델의
showLocationList
불리언 변수를 토글하는 함수
- 애니메이션 효과 적용
func showNextLocation(location: LocationModel) {
withAnimation(.easeInOut) {
mapLocation = location
showLocationList = false
}
}
- 뷰 모델의
mapLocation
데이터 퍼블리셔 값을 변경함으로써 현재 선택된 지역 정보를 업데이트
- 펼쳐진 리스트 뷰를 자동으로 닫도록
showLocationList
값 또한 설정
구현 화면