选择要显示的新项目时,iPad 上的 NavigationStack 中不会调用 SwiftUI .onAppear

问题描述 投票:0回答:1

我正在构建一个应用程序,它显示可供选择的位置列表,然后推送该位置的详细视图以及显示该位置的地图。 当我在 iPhone 上使用此代码时,一切都会按预期工作,但是,当我在 iPad 上使用它时,我用来设置地图区域和图钉的 onAppear 方法永远不会被后续位置调用。 我认为这与屏幕上始终显示的细节有关。

var body: some View {
        List(locations, id: \.id) { location in
            NavigationLink(value: location) {
                LocationRowView(location: location)
            }
        }
        .navigationDestination(for: Location.self) { location in
            LocationView(location: location)
        }
        .listStyle(.plain)
    }

和位置视图

struct LocationView: View {
    var location: Location
    
    @State private var position: MapCameraPosition = .automatic

    private var locationCoordinate: CLLocationCoordinate2D {
        CLLocationCoordinate2D(latitude: location.address.latitude, longitude: location.address.longitude)
    }
    
    private var locationRegion: MKCoordinateRegion {
        MKCoordinateRegion(center: locationCoordinate, span: MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05))
    }
    
    private var locationPosition: MapCameraPosition {
        MapCameraPosition.region(locationRegion)
    }

    var body: some View {
        VStack {
            Map(position: $position) {
                Marker("", coordinate: locationCoordinate)
            }
        }.navigationBarTitleDisplayMode(.inline)
        .onAppear {
            position = locationPosition
        }
    }
}

需要明确的是,当我在 iPad 上运行此代码时,我会看到一个侧边栏,其中包含我的位置列表,后面有一个空白的详细信息屏幕,正如预期的那样。 当我选择一个位置时,我会看到详细信息屏幕,其中显示带有所选位置图钉的地图。 现在的错误是,当我选择不同的位置时,图钉会移动,但当我期望地图也会移动并使新图钉居中时,地图仍保持在第一个位置的中心。

我编写的代码应该将地图集中在传入的位置坐标上,这是第一次通过输入

.onAppear
修饰符来实现,但在后续位置选择中不会发生这种情况。

如果我删除

.onAppear
调用并将位置保留为
.automatic
,则后续选择会移动地图并显示新的图钉,除非我以任何方式(缩放、平移等)与地图进行交互。

ios swiftui ipad
1个回答
0
投票

您可以将

onAppear
更改为
onChange
。传递
initial: true
,以便在视图第一次出现时触发。

.onChange(of: locationPosition, initial: true) { _, newValue in
    position = newValue
}

也就是说,使用

navigationDestination
这种方式导航到详细视图(尽管它有效)没有记录。我建议使用
List
的选择来驱动
NavigationSplitView

这是一个例子:

struct Location: Identifiable, Hashable {
    let id = UUID()
    let address: CLLocationCoordinate2D
    let name: String
    
    // Hashable implementation omitted
}

let locations = [
    Location(address: .init(latitude: 40.776863, longitude: -73.874069), name: "Foo"),
    Location(address: .init(latitude: 25.795160, longitude: -80.279594), name: "Bar"),
]

struct ContentView: View
{
    
    @State var selection: Location?

    var body: some View {
        NavigationSplitView {
            LocationList(selection: $selection)
        } detail: {
            if let selection {
                LocationView(location: selection)
            }
        }
    }
}

struct LocationList: View {
    @Binding var selection: Location?
    
    var body: some View {
        List(locations, selection: $selection) { location in
            NavigationLink(value: location) {
                Text(location.name)
            }
        }
        .listStyle(.plain)
    }
}

struct LocationView: View {
    var location: Location
    
    @State private var position: MapCameraPosition = .automatic

    private var locationCoordinate: CLLocationCoordinate2D {
        CLLocationCoordinate2D(latitude: location.address.latitude, longitude: location.address.longitude)
    }
    
    private var locationRegion: MKCoordinateRegion {
        MKCoordinateRegion(center: locationCoordinate, span: MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05))
    }
    
    private var locationPosition: MapCameraPosition {
        MapCameraPosition.region(locationRegion)
    }

    var body: some View {
        VStack {
            Map(position: $position) {
                Marker("", coordinate: locationCoordinate)
            }
        }
        .navigationBarTitleDisplayMode(.inline)
        .onChange(of: locationPosition, initial: true) { _, newValue in
            position = newValue
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.