我正在构建一个应用程序,它显示可供选择的位置列表,然后推送该位置的详细视图以及显示该位置的地图。 当我在 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
,则后续选择会移动地图并显示新的图钉,除非我以任何方式(缩放、平移等)与地图进行交互。
您可以将
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
}
}
}