[SwiftUI] MapClone: Location DetailView

Junyoung Park·2022년 12월 16일
0

SwiftUI

목록 보기
134/136
post-thumbnail
post-custom-banner

Use Sheet in SwiftUI to create a Detail View for Locations | SwiftUI Map App #7

MapClone: Location DetailView

구현 목표

  • 로케이션 선택 시 디테일 뷰 구현

구현 태스크

핵심 코드

 private var learnMoreButton: some View {
        Button {
            viewModel.sheetLocation = location
        } label: {
            Text("Learn more")
                .font(.headline)
                .frame(maxWidth: 125, maxHeight: 30)
        }
        .buttonStyle(.borderedProminent)
    }
  • 버튼 클릭 시 sheetLocation 변수에 값을 할당
.sheet(item: $viewModel.sheetLocation, onDismiss: nil) { location in
            LocationDetailView(location: location)
        }
  • 뷰 모델의 sheetLocation 값이 널이 아닐 때 자동으로 모달 뷰가 띄워지는 구조
private var backButton: some View {
        Button {
            viewModel.sheetLocation = nil
        } label: {
            Image(systemName: "xmark")
                .font(.headline)
                .padding(16)
                .foregroundColor(.primary)
                .background(.thickMaterial)
                .cornerRadius(10)
                .shadow(radius: 4)
                .padding()
        }

    }
  • 모달 뷰 위에 오버레이를 통해 좌측 상단에 띄운 백버튼
  • 뷰 모델의 sheetLocation에 직접 널을 할당함으로써 모달 시트를 내리기
import SwiftUI
import MapKit

struct LocationDetailView: View {
    @EnvironmentObject private var viewModel: LocationsViewModel
    let location: LocationModel
    var body: some View {
        GeometryReader { geometry in
            ScrollView {
                VStack {
                    getImageSection(geometry: geometry)
                        .shadow(color: Color.black.opacity(0.3), radius: 20, x: 0, y: 10)
                    VStack(alignment: .leading, spacing: 20) {
                        titleSection
                        Divider()
                        descriptionSection
                        Divider()
                        mapLayer
                    }
                    .frame(maxWidth: .infinity, alignment: .leading)
                    .padding()
                }
            }
            .ignoresSafeArea()
            .background(.ultraThinMaterial)
            .overlay(
                backButton, alignment: .topLeading
            )
        }
    }
}
  • 전체적인 로케이션 디테일 뷰 구조
  • 디바이스 크기를 읽기 위한 GeometryReader 사용
private var mapLayer: some View {
        Map(coordinateRegion: .constant(MKCoordinateRegion(
            center: location.coordinates,
            span: .init(latitudeDelta: 0.01, longitudeDelta: 0.01))),
            annotationItems: [location]) { location in
            MapAnnotation(coordinate: location.coordinates) {
                LocationMapAnnotationView()
                    .shadow(radius: 10)
            }
        }
            .allowsHitTesting(false)
            .aspectRatio(1, contentMode: .fit)
            .cornerRadius(30)
    }
  • 맵뷰 클릭 이벤트를 방지하기 위해 allowHitTesting을 통해 false를 전달
  • aspectRatiocontentMode를 통해 1 대 1 비율의 정사각형 구조

구현 화면

profile
JUST DO IT
post-custom-banner

0개의 댓글