Как структурировать SwiftUI, чтобы страницы сохраняли свое состояние при переключении между различными макетами пользоваIOS

Программируем под IOS
Ответить
Anonymous
 Как структурировать SwiftUI, чтобы страницы сохраняли свое состояние при переключении между различными макетами пользова

Сообщение Anonymous »

У меня есть представление SwiftUI, которое переключается между двумя совершенно разными макетами контейнеров:
  • макет TabView (для компактной ширины)
  • макет боковой панели + содержимого с использованием HStack (для обычной ширины). Я использую пользовательскую боковую панель, поскольку здесь требуется больше макетов и настроек)
Контейнер может динамически изменяться во время выполнения, например повернув устройство или с помощью переключателя (см. демонстрационный код ниже). Дочерние страницы содержат свои собственные модели представления @StateObject.
Важно: Различные макеты — это не протоколы SwiftUI Layout, а представления, которые не только управляют размещением различных представлений, но также управляют тем, какое подпредставление отображается и т. д. (например, TabView содержит подпредставления и показывает представление, когда выбрана соответствующая вкладка).
Проблема:
if useTabLayout {
TabLayoutContainer(...)
} else {
SidbarLayoutContainer(...)
}

Когда я переключаюсь между двумя макетами контейнеров, страницы создаются заново, что означает, что их модели представления @StateObject повторно инициализируются, а состояние представления теряется.
Чего я хочу:
  • PageOne, PageTwo и PageThree должны сохранять свое состояние
  • переключение между макетом вкладок и макетом боковой панели не должно воссоздать страницы
  • должен измениться только внешний контейнер
До сих пор пробовал:
  • Использование .id(...) на страницах (например, PageOne().id("one")). Модель представления все еще создается заново.
  • Создание модели представления страницы в Root-View и внедрение ее на страницы как @ObservedObject. Хотя это работает, для этого требуется, чтобы Root-View знал о просмотрах страниц и их содержании. Кажется, это не совсем чистое решение.
  • Создание страниц только один раз: пусть pageOne = PageOne() и case .pageOne: возвращает pageOne. Кажется, это тоже работает. Но есть ли какие-либо недостатки в таком сохранении страницы?
  • Учитывая AnyLayout (но он работает только для реальных макетов, таких как VStackLayout, а не для сложных контейнеров, таких как TabView)
Вопрос
Каков правильный подход SwiftUI для сохранения состояния дочернего представления (@StateObject) жив при переключении между двумя совершенно разными представлениями контейнера (TabView и Sidebar+Content)?
Демо-код
enum MyPage: Hashable {
case pageOne, pageTwo, pageThree
}

struct MyRootView: View {
@State var useTabLayout = true
@State var selectedPage: MyPage = .pageOne

var body: some View {
VStack {
Toggle("TabLayout", isOn: $useTabLayout)

if useTabLayout {
TabLayoutContainer(selectedPage: $selectedPage)
} else {
SidbarLayoutContainer(selectedPage: $selectedPage)
}
}
}
}

struct TabLayoutContainer: View {
@Binding var selectedPage: MyPage

var body: some View {
TabView(selection: $selectedPage) {
PageFactory.view(for: .pageOne)
.tag(MyPage.pageOne)

PageFactory.view(for: .pageTwo)
.tag(MyPage.pageTwo)

PageFactory.view(for: .pageThree)
.tag(MyPage.pageThree)
}
}
}

struct SidbarLayoutContainer: View {
@Binding var selectedPage: MyPage

var body: some View {
HStack {
// Sidebar
VStack {
Button("One") { selectedPage = .pageOne }
Button("Two") { selectedPage = .pageTwo }
Button("Three") { selectedPage = .pageThree }
}

// Content
VStack {
PageFactory.view(for: selectedPage)
}
}
}
}

@ViewBuilder
static func view(for page: MyPage) -> some View {
switch page {
case .pageOne: PageOne()
case .pageTwo: PageTwo()
case .pageThree: PageThree()
}
}

struct PageOne: View {
@StateObject var viewModel: ViewModelOne = .init()

var body: some View {
Text("Page One")
}

class ViewModelOne: ObservableObject {
init() {
print("Initialized ViewModelOne")
}
}
}


Подробнее здесь: https://stackoverflow.com/questions/798 ... -between-d
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «IOS»