SwiftUI — время добавления представлений в иерархию окон при использовании списка

#ios #swift #swiftui

#iOS #swift #swiftui

Вопрос:

Я создаю приложение SwiftUI для iPhone и iPad, которое начинается со списка. Каждая запись представляет другое представление, к которому пользователь может перейти. Для каждого представления может потребоваться объяснение, поэтому я хотел бы показать его при первом переходе пользователя к ним. Я пытаюсь использовать fullScreenCover , чтобы показать это «вводное представление».

Но когда полноэкранный режим пытается показать, я получаю следующее, и, следовательно, вводный вид никогда не отображается:

 2020-10-22 09:55:05.587361-0700 test[81095:3217286] [Presentation] Attempt to present
<_TtGC7SwiftUI22SheetHostingControllerVS_7AnyView_: 0x7f883e51bcc0> on
<_TtGC7SwiftUI41StyleContextSplitViewNavigationControllerVS_14NoStyleContext_: 0x7f883e819a00> 
(from <_TtGC7SwiftUIP13$7fff562fec9428DestinationHostingControllerVS_7AnyView_: 0x7f883e4169b0>) 
whose view is not in the window hierarchy.
  

Я понимаю, что ошибка заключается в том, что я пытаюсь представить представление поверх другого, которого еще нет в иерархии представлений окна. Я сталкивался с другими вопросами, которые задают похожие вопросы, и решение состояло в том, чтобы подождать, пока вы не получите уведомление о том, что представление отображается на экране (через viewDidAppear и тому подобное). Но у меня есть некоторые наблюдения, которые заставляют меня думать, что это другой случай:

  • Ошибка возникает только тогда, когда NavigationLink переход к подробному представлению находится внутри a List (см. Код ниже). Когда вне a List все работает нормально.

  • Ошибка также возникает только на iPhone. На целевом устройстве iPhone я получаю сообщение об ошибке, когда объект NavigationLink находится внутри a List , но все работает, когда это не так. На цели iPad конечная fullScreenCover работа работает независимо от того, была ли NavigationLink она внутри a List или нет.

    • До сих пор вся моя работа была в симуляторе, если это имеет значение.

Ниже приведен код, который воспроизводит проблему. Обратите внимание на закомментированный List контейнер MainAppView . Если я запускаю его как есть на iPhone, вид ввода отображается. Если я раскомментирую List контейнер, я получу сообщение об ошибке. Я понимаю, что мне чего-то не хватает в том, как изменяется иерархия представлений при использовании a List , и это как-то отличается, когда вы находитесь в разных классах размеров. Но я не совсем понимаю, что это такое или где об этом узнать. Любая помощь будет с благодарностью принята.

 import SwiftUI

struct MainAppView: View {
    var body: some View {
        NavigationView {
//            List {  // <-- Uncomment this line (and closing brace 3 lines down) to hit issue
                NavigationLink(destination: ComplicatedView()) {
                    Text("Go to complicated view")
                }
//            }
        }
    }
}

struct ComplicatedView: View {
    @State private var showingCover = true

    var body: some View {
        DetailsOfComplicatedView()
        .fullScreenCover(isPresented: $showingCover, content: {
            TutorialView()
        })
    }
}

struct DetailsOfComplicatedView: View {
    var body: some View {
        VStack {
            Text("Some nitty gritty details go here.")
            Text("But if it all goes right, it should immediately get covered up by a tutorial view. Does it?")
        }
    }
}

struct TutorialView: View {
    var body: some View {
        VStack {
            Text("I'd like to take a moment and explain this complicated view.")
            Button("OK") {
                // Do something to dismiss. But not relevant to the question.
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        MainAppView()
    }
}
  

Ответ №1:

Немного рано, появилась активация полноэкранного режима при просмотре, как показано ниже (протестировано с Xcode 12 / iOS 14)

 struct ComplicatedView: View {
    @State private var showingCover = false

    var body: some View {
        DetailsOfComplicatedView()
        .fullScreenCover(isPresented: $showingCover, content: {
            TutorialView()
        })
        .onAppear { self.showingCover = true }
    }
}
  

Комментарии:

1. Спасибо Asperi; это действительно работает. Мне любопытно, почему исходный код (т. Е. Без onAppear ) Не будет работать на iPhone, когда он находится внутри списка? Каждый пример fullScreenCover , который я видел, заставляет думать, что так и должно быть. Это просто новый API, который не работает?