#swiftui #swiftui-state
#swiftui #swiftui-состояние
Вопрос:
Моя цель — передавать значения между представлениями, от Chooser к ThemeEditor. Когда пользователь нажимает значок, я сохраняю объект, который хочу передать, и позже, используя sheet
и передавая вновь созданное представление с содержимым @State var
.
Присвоение выполняется успешно @State var themeToEdit
, однако это происходит nil
при создании ThemeEditor
представления в sheet
Что я делаю не так?
struct Chooser: View {
@EnvironmentObject var store: Store
@State private var showThemeEditor = false
@State private var themeToEdit: ThemeContent?
@State private var editMode: EditMode = .inactive
@State private var isValid = false
var body: some View {
NavigationView {
List {
ForEach(self.store.games) { game in
NavigationLink(destination: gameView(game))
{
Image(systemName: "wrench.fill")
.imageScale(.large)
.opacity(editMode.isEditing ? 1 : 0)
.onTapGesture {
self.showThemeEditor = true
/* themeInfo is of type struct ThemeContent: Codable, Hashable, Identifiable */
self.themeToEdit = game.themeInfo
}
VStack (alignment: .leading) {
Text(self.store.name(for: something))
HStack{
/* some stuff */
Text(" of: ")
Text("Interesting info")
}
}
}
}
.sheet(isPresented: $showThemeEditor) {
if self.themeToEdit != nil { /* << themeToEdit is nil here - always */
ThemeEditor(forTheme: self.themeToEdit!, $isValid)
}
}
}
.environment(.editMode, $editMode)
}
}
}
struct ThemeEditor: View {
@State private var newTheme: ThemeContent
@Binding var isValid: Bool
@State private var themeName = ""
init(forTheme theme: ThemeContent, isValid: Binding<Bool>) {
self._newTheme = State(wrappedValue: theme)
self._validThemeEdited = isValid
}
var body: some View {
....
}
}
struct ThemeContent: Codable, Hashable, Identifiable {
/* stores simple typed variables of information */
}
Ответ №1:
Представление .sheet
содержимого фиксируется в момент создания, поэтому, если вы хотите что-то проверить внутри, вам нужно использовать .sheet(item:)
variant, например
.sheet(item: self.$themeToEdit) { item in
if item != nil {
ThemeEditor(forTheme: item!, $isValid)
}
}
Примечание: неясно, что это ThemeContent
такое, но это может потребоваться для соответствия дополнительным протоколам.
Ответ №2:
Использовать Binding
. Измените представление редактора темы с помощью этого.
struct ThemeEditor: View {
@Binding private var newTheme: ThemeContent?
@Binding var isValid: Bool
@State private var themeName = ""
init(forTheme theme: Binding<ThemeContent?>, isValid: Binding<Bool>) {
self._newTheme = theme
self._isValid = isValid
}
var body: some View {
....
}
}
И для кода листа
.sheet(isPresented: $showThemeEditor) {
ThemeEditor(forTheme: $themeToEdit, isValid: $isValid)
}
При действии
.onTapGesture {
/* themeInfo is of type struct ThemeContent: Codable, Hashable, Identifiable */
self.themeToEdit = game.themeInfo
self.showThemeEditor = true
}
Комментарии:
1. Спасибо — я принял ответ @Asperi, поскольку он объяснил, что происходит и почему я получаю неожиданное поведение. Поскольку я начинаю с SwiftUI, я предпочитаю это как ответ, а не как работоспособный обходной путь.
2. да, я согласен, но, пожалуйста, обратите внимание. это не обходной ответ.