SwiftUI NavigationLink появляется автоматически, что неожиданно
У меня возникли проблемы с NavigationLink на iPad с разделенным экраном (альбомная ориентация). Вот пример:
Вот код для воспроизведения проблемы:
import SwiftUI
final class MyEnvironmentObject: ObservableObject {
@Published var isOn: Bool = false
}
struct ContentView: View {
@EnvironmentObject var object: MyEnvironmentObject
var body: some View {
NavigationView {
NavigationLink("Go to FirstDestinationView", destination: FirstDestinationView(isOn: $object.isOn))
}
}
}
struct FirstDestinationView: View {
@Binding var isOn: Bool
var body: some View {
NavigationLink("Go to SecondDestinationView", destination: SecondDestinationView(isOn: $isOn))
}
}
struct SecondDestinationView: View {
@Binding var isOn: Bool
var body: some View {
Toggle(isOn: $isOn) {
Text("Toggle")
}
}
}
// Somewhere in SceneDelegate
ContentView().environmentObject(MyEnvironmentObject())
Кто-нибудь знает, как это исправить? Простое решение - отключить режим разделения экрана, но для меня это невозможно.
4 ответа
Хорошо, вот результаты моего расследования (протестировано с Xcode 11.2), а ниже - код, который работает.
В iPad NavigationView
попал в стиль Master/Details, поэтому ContentView
если начальная ссылка активна и привязки процесса обновляются из environmentObject, поэтому обновите, что приведет к активации ссылки просмотра сведений через ту же привязку, что приведет к повреждению стека навигации. (Примечание: это отсутствует в iPhone из-за стиля стека, который отключает корневое представление).
Так что, вероятно, это обходной путь, но он работает - идея состоит не в том, чтобы передавать привязку из представления в представление, а в использовании environmentObject непосредственно в окончательном представлении. Возможно, так будет не всегда, но в любом случае в таких сценариях необходимо избегать обновления корневого представления, поэтому оно не должно иметь такой же привязки в теле. Что-то подобное.
final class MyEnvironmentObject: ObservableObject {
@Published var selection: Int? = nil
@Published var isOn: Bool = false
}
struct ContentView: View {
@EnvironmentObject var object: MyEnvironmentObject
var body: some View {
NavigationView {
List {
NavigationLink("Go to FirstDestinationView", destination: FirstDestinationView())
}
}
}
}
struct FirstDestinationView: View {
var body: some View {
List {
NavigationLink("Go to SecondDestinationView", destination: SecondDestinationView())
}
}
}
struct SecondDestinationView: View {
@EnvironmentObject var object: MyEnvironmentObject
var body: some View {
VStack {
Toggle(isOn: $object.isOn) {
Text("Toggle")
}
}
}
}
Когда что-то внутри
EnvironmentObject
изменения, он снова отобразит весь вид, включая
NavigationLink
. Это основная причина автоматического возврата.
Мои исследования по этому поводу:
- ОК на iOS 15 (похоже, Apple исправила)
- Все еще не работает на iOS 14
- Причина, по которой «Эта ошибка исчезла, когда я отказался от @EnvironmentObject и вместо этого выбрал @ObservedObject». @Jon Vogel упомянул, что ObservedObject - это локальное состояние, на которое не будут влиять другие представления, в то время как EnvironmentObject является глобальным состоянием и может изменяться из любых других удаленных представлений.
Вам нужно использовать isDetailLink(_:) , чтобы исправить это, например
struct FirstDestinationView: View {
@Binding var isOn: Bool
var body: some View {
NavigationLink("Go to SecondDestinationView", destination: SecondDestinationView(isOn: $isOn))
.isDetailLink(false)
}
}
Эта ошибка исчезла, когда я уронил @EnvironmentObject
и пошел с @ObservedObject
вместо.