KaitoKudou / nogizaka-pilgrimage

0 stars 0 forks source link

iOS17対応のMapKitに差し替え #66

Open KaitoKudou opened 6 months ago

KaitoKudou commented 5 months ago

こんな要領で

struct PilgrimageMapView: View {
    @Environment(\.theme) private var theme
    @State private var visibleRegion: MKCoordinateRegion?
    @State private var region = PilgrimageMapConstant.initialRegion
    @State private var position = PilgrimageMapConstant.initialCameraPosition
    @State private var selectedIndex: Int = 0
    @State private var isShowAlert = false
    @EnvironmentObject private var locationManager: LocationManager
    let pilgrimages: [PilgrimageInformation]

    var body: some View {
        GeometryReader { geometry in
            mapView
                .ignoresSafeArea(edges: [.bottom])
                .overlay(alignment: .topTrailing) {
                    CurrentLocationButton {
                        let isAuthorized = !locationManager.isLocationPermissionDenied
                        guard isAuthorized else {
                            // 位置情報が許可されなかった場合
                            isShowAlert.toggle()
                            return
                        }
                        guard let location = locationManager.userLocation else {
                            return
                        }
                        withAnimation {
//                            self.region.center = offsetAppliedCenter(to: location, geometry: geometry)

                            position = MapCameraPosition.region(
                                (offsetAppliedCenter(
                                    to: location, geometry: geometry
                                ) ?? PilgrimageMapConstant.initialCameraPosition.region)!
                            )
                        }
                    }
                    .alert(R.string.localizable.alert_location(), isPresented: $isShowAlert) {
                    } message: {
                        EmptyView()
                    }

                }
                .overlay(alignment: .bottom) {
                    pilgrimageCardsView(geometry: geometry)
                        .padding(.bottom, theme.margins.spacing_xl)
                }
                .onAppear {
                    locationManager.requestLocation()
                }
                .onChange(of: selectedIndex) { _, _ in
                    withAnimation {
                        position = MapCameraPosition.region(
                            (offsetAppliedCenter(
                                to: pilgrimages[selectedIndex].coordinate,
                                geometry: geometry
                            ) ?? PilgrimageMapConstant.initialCameraPosition.region)!
                        )

//                        region.center = offsetAppliedCenter(
//                            to: pilgrimages[selectedIndex].coordinate,
//                            geometry: geometry
//                        )
                    }
                }
                .onMapCameraChange { mapCameraUpdateContext in
                    visibleRegion = mapCameraUpdateContext.region
                }
        }
    }

    private var mapView: some View {
        Map(position: $position) {
            ForEach(pilgrimages) { pilgrimage in
                let index = pilgrimages.firstIndex(where: { $0.code == pilgrimage.code }) ?? 0

                Annotation(coordinate: pilgrimage.coordinate) {
                    Image(uiImage: R.image.map_pin()!)
                        .onTapGesture {
                            selectedIndex = index
                        }
                } label: {
                    Text("")
                }
            }
        }

//        Map(
//            coordinateRegion: $region,
//            showsUserLocation: true,
//            annotationItems: pilgrimages,
//            annotationContent: { item in
//                let coordinate = CLLocationCoordinate2D(
//                    latitude: item.coordinate.latitude,
//                    longitude: item.coordinate.longitude
//                )
//                let index = pilgrimages.firstIndex(where: { $0.code == item.code }) ?? 0
//
//                return MapAnnotation(coordinate: coordinate) {
//                    Image(uiImage: R.image.map_pin()!)
//                        .onTapGesture {
//                            selectedIndex = index
//                        }
//                }
//            }
//        )
    }

    private func pilgrimageCardsView(geometry: GeometryProxy) -> some View {
        TabView(selection: $selectedIndex) {
            ForEach(Array(pilgrimages.enumerated()), id: \.element.id) { index, pilgrimage in
                PilgrimageCardView(pilgrimage: pilgrimage)
                .tag(index)
                .frame(
                    width: max(0, geometry.size.width - theme.margins.spacing_l * 2)
                )
            }
        }
        .tabViewStyle(.page(indexDisplayMode: .never))
        .frame(height: cardsHeight(geometry: geometry))
    }

    private func cardsHeight(geometry: GeometryProxy) -> CGFloat {
        return max(0, geometry.size.width / 2 - theme.margins.spacing_m)
    }

    private func offsetAppliedCenter(to center: CLLocationCoordinate2D, geometry: GeometryProxy) -> CLLocationCoordinate2D {
        let ratio = (cardsHeight(geometry: geometry) / 2) / geometry.size.height
        let latitudeOffset = ratio * region.span.latitudeDelta
        let coordinate = CLLocationCoordinate2D(
            latitude: center.latitude - latitudeOffset,
            longitude: center.longitude
        )
        return coordinate
    }

    private func offsetAppliedCenter(to center: CLLocationCoordinate2D, geometry: GeometryProxy) -> MKCoordinateRegion? {
        let ratio = (cardsHeight(geometry: geometry) / 2) / geometry.size.height
        guard let visibleRegion = visibleRegion else { return nil }
        let latitudeDelta = visibleRegion.span.latitudeDelta
        let latitudeOffset = ratio * latitudeDelta
        return MKCoordinateRegion(
            center: CLLocationCoordinate2D(
                latitude: center.latitude - latitudeOffset,
                longitude: center.longitude
            ),
            span: visibleRegion.span
        )
    }
}
KaitoKudou commented 5 months ago
/// MapCameraPositionの初期値
    /// 乃木坂駅を指定。
    static let initialCameraPosition = MapCameraPosition.region(
        MKCoordinateRegion(
            center: CLLocationCoordinate2D(
                latitude: 35.666827, longitude: 139.726497
            ),
            latitudinalMeters: initialLatitudinalMeters,
            longitudinalMeters: initialLongitudinalMeters
        )
    )