Сброс NavigationSplitView, когда приложение переходит в фоновый режим
Я пытался создать приложение с использованием NavigationSplitView и SwiftUI на iOS 16. Я заметил, что почти как только приложение переходит в фоновый режим (иногда мне приходится подождать несколько секунд, прежде чем немедленно снова открыть приложение), содержимое NavigationSplitView становится перезагрузить. Это поведение отличается от NavigationStack, использующего по существу тот же путь и структуру приложения. Мне интересно, есть ли у кого-нибудь идеи, почему это происходит?
Я провел небольшое расследование и могу сказать, что заметил несколько вещей.
При использовании списка с указанным элементом выбора элемент выбора устанавливается в ноль, когда приложение переходит в фоновый режим. Для NavigationSplitView это обычно приводит к сбросу нижестоящего представления подробностей или содержимого, поскольку значение теряется.
Если использовать список без указанного параметра выбора, этот эффект смягчается, но представление все равно сбрасывается, а такие вещи, как положение прокрутки, стираются, несмотря на отсутствие изменения содержимого. Self._printChanges() указывает, что представление не изменилось, несмотря на сброс в исходное состояние.
Этот эффект воспроизводится с помощью собственного примера приложения Apple WWDC.
В этом примере приложения есть некоторая логика, которая пытается сохранить данные пути навигации, но на самом деле все равно не работает, но в целях тестирования я закомментировал это.
Внутри ContentView.swift
// .task {
// if let jsonData = navigationData {
// navigationModel.jsonData = jsonData
// }
// for await _ in navigationModel.objectWillChangeSequence {
// navigationData = navigationModel.jsonData
// }
// }
Это приложение является хорошим примером, поскольку вы можете переключаться между NavigationStack и NavigationSplitView, а поведение изолировано от NavigationSplitView, и NavigationStack не сбрасывается немедленно.
Очевидно, сохранение состояния — это вариант, но он добавляет немало накладных расходов, а такие вещи, как положение прокрутки, трудно воспроизвести точно, и необходимость прибегать к этому, когда приложение теряет фокус всего на несколько секунд, не идеальна, мне интересно. есть ли обходной путь или это ошибка, тем более что этого не было при использовании NavigationStack. Я тестировал это на последней бета-версии iOS 17 с тем же эффектом.
Включая ссылку на видео, показывающую проблему https://youtu.be/cKicWv_58_s.
Я также попробовал создать небольшой пример приложения с использованием NavigationView с макетом из трех столбцов, и это работает нормально, поэтому кажется, что оно изолировано от NavigationSplitView.
Я также включил небольшой, более простой пример, чем приведенный ниже пример WWDC, который можно использовать для демонстрации проблемы и показывает, что NavigationView работает нормально.
import SwiftUI
struct ContentView: View {
@State var presentingNSV: Bool = false
@State var presentingNV: Bool = false
var body: some View {
HStack {
Button {
presentingNSV.toggle()
} label: {
Text("NavigationSplitView")
}
Button {
presentingNV.toggle()
} label: {
Text("NavigationView")
}
}
.fullScreenCover(isPresented: $presentingNSV) {
NSV(isPresented: $presentingNSV)
}
.fullScreenCover(isPresented: $presentingNV) {
NV(isPresented: $presentingNV)
}
}
}
struct TestList: View {
var body: some View {
List(0..<1000) { item in
Text("Item \(item)")
}
}
}
struct NSV: View {
@Binding var isPresented: Bool
var body: some View {
let _ = Self._printChanges()
NavigationSplitView {
TestList()
.toolbar {
ToolbarItem {
Button {
isPresented = false
} label: {
Text("Back")
}
}
}
} content: {
TestList()
} detail: {
TestList()
}
}
}
struct NV: View {
@Binding var isPresented: Bool
var body: some View {
let _ = Self._printChanges()
NavigationView {
TestList()
.toolbar {
ToolbarItem {
Button {
isPresented = false
} label: {
Text("Back")
}
}
}
TestList()
TestList()
}
.navigationViewStyle(.columns)
}
}
Видео с использованием этого примера кода https://youtu.be/GAiRL8TprrM