Я пытаюсь реализовать список ссылок навигации, который позволит мне перемещаться между представлениями до 3 уровней ссылок навигации.
Основной вид -> Просмотр2 -> Просмотр3 -> Просмотр4
Когда я дойду до View4, в представлении не будет кнопки «Назад» по умолчанию на панели навигации, но вместо этого будет кнопка, которая позволит мне вернуться к «Основному представлению».
Используя решение, упомянутое здесь, я смог (вроде) достичь того, что хотел, внеся небольшие изменения в решение, так что бит isActive реализован как массив бит isActive, каждый из которых соответствует количеству навигационных ссылок, которые повторяются в контейнер списка.
Единственная проблема, которую я заметил, заключается в том, что операция просмотра pop-to-root с использованием битов isActive будет работать только в том случае, если я использую ее с оболочкой свойств @State, но ничего не будет делать, если мои биты isActive содержатся в экземпляре класса ObservableObject. Моя проблема с использованием оболочки @State заключается в том, что мне придется предварительно определить фиксированный размер массива и заполнить его «ложными» битами, которые мне не нужны, поскольку количество элементов, которые я могу перебирать в контейнере List, может варьироваться. поэтому я хочу, чтобы размер массива isActive был таким же, как количество элементов, которые я повторяю в контейнере List.
Вот упрощенная реализация кода NavigationView для всплывающего сообщения в корневой каталог для справки. Верхняя половина NavigationLinks - это те, которые используют битовый массив isActive фиксированного размера с оболочкой @State, которая работает, в то время как нижняя половина NavigationLinks - это те, которые используют наблюдаемый объект, который может иметь гибкий размер битового массива isActive, но Кажется, я не могу понять, почему этот подход не работает.
Главный вид:
struct ContentView: View {
@ObservedObject var itemGroup: ItemGroup
// If I use @State wrapper, I need to pre allocate a fixed array size and populate
// it with 'false' values.
@State var isActive: [Bool] = [false, false, false, false]
var body: some View {
NavigationView {
VStack {
// MARK: Navigation links using isActive property with @State wrapper
// (this implementation works but the isActive array size needs to be defined
// with a fixed size, I would prefer the size to be variable)
List(1..<5) { item in
NavigationLink(destination: View2(isActive: $isActive[item-1], sub: "sub\(item)"), isActive: $isActive[item-1]) {
Text("Go to view 2 using @State, sub\(item)")
.padding()
.background(Color.blue)
.foregroundColor(.white)
}
}
// MARK: Navigation links using isActive property defined within an observable
// class object
// (I would have preferred this method since I can have the
// flexibility of allocating an isActive array based on the number of
// NavigationLink views generated by the list container but the pop-to-root
// operation won't work with this approach)
// Note: The range 1..<5 is used here for illustration purposes only but is actually an array of objects whose array size may vary
List(1..<5) { item in
NavigationLink(destination: View2(isActive: $itemGroup.isActive[item-1], sub: "sub\(item)"), isActive: $itemGroup.isActive[item-1]) {
Text("Go to view 2, sub\(item)")
.padding()
.background(Color.blue)
.foregroundColor(.white)
}
}
.navigationBarTitle("Main view")
}
}
}
}
class ItemGroup: ObservableObject {
@Published var isActive: [Bool] = []
init() {
// Note: The range 1..<5 is used only for illustration purposes only.
// In my use case, this is actually an array of objects whose array size may vary.
for _ in 1..<5 {
isActive.append(false)
}
}
}
View2:
struct View2: View {
@Binding var isActive: Bool
@State var sub: String
var body: some View {
NavigationLink(destination: View3(isActive: $isActive)) {
Text("Go to view 3")
.padding()
.background(Color.blue)
.foregroundColor(.white)
}
.navigationBarTitle("View 2, \(sub)")
}
}
View3:
struct View3: View {
@Binding var isActive: Bool
var body: some View {
NavigationLink(destination: View4(isActive: $isActive)) {
Text("Go to view 4")
.padding()
.background(Color.blue)
.foregroundColor(.white)
}
.navigationBarTitle("View 3")
}
}
View4 (это тот, у которого есть функция просмотра pop-to-root):
struct View4: View {
@Binding var isActive: Bool
var body: some View {
VStack {
Text("View 4")
Button("Back to Main View", action: {
isActive = false
})
.padding()
.background(Color.blue)
.foregroundColor(.white)
}
.navigationBarHidden(true)
}
}
Вот демонстрации двух разных реализаций в формате gif.
Навигация с использованием массива isActive с оболочкой свойств @State (нажмите ссылку)
Навигация с использованием массива isActive внутри наблюдаемого объекта (щелкните ссылку)
Может ли кто-нибудь помочь мне понять, почему нижняя половина NavigationLinks не работает и какие изменения мне нужно сделать, чтобы она работала?
Цените помощь. Спасибо.
Голос против был не моим, но я проголосовал против него. Я считаю, что ваш вопрос правильно сформулирован и ясен. Проблема сосредоточена вокруг взаимосвязи между ObservableObject
и List
- если вы измените List
на ForEach
, все будет работать, как ожидалось. Хотелось бы, чтобы у меня было легкое решение, но я не нашел что-то надежно работающее. Но я продолжу поиски.
Спасибо @jnpdx за голосование и за то, что он сообщил мне, что ObservableObject и List плохо сочетаются друг с другом. Я не знаю об этом поведении, но я прочитаю об этом, чтобы узнать, почему. Думаю, сейчас я могу работать с ForEach вместо List. Чтобы учесть отсутствующую графику «>», которую предоставляет контейнер List, я, вероятно, могу просто включить изображение символа SF для «>», чтобы имитировать, как будет выглядеть контейнер List. Я буду продолжать следить за более легким обходным путем или исправлением, которое вы сможете найти в будущем. Цените помощь.
Я надеюсь, что человек, проголосовавший против моего вопроса, опубликует причину, по которой он проголосовал против. Как новый автор, я хотел бы знать, что я сделал не так, чтобы заслужить голос против, чтобы я не повторял ту же ошибку в будущем.