@ State
Чтобы понять это, нам нужно сначала коснуться @State
. Что это?
SwiftUI управляет хранением любого свойства, которое вы объявляете как состояние. Когда значение состояния изменяется, представление делает его недействительным и пересчитывает тело.
...
Экземпляр состояния не является самим значением ; это средство чтения и записи значения. Чтобы получить доступ к базовому значению состояния, используйте имя его переменной, которое возвращает значение свойства wrappedValue.
Ref: https://developer.apple.com/documentation/swiftui/state
Но почему нам нужно было @State
? Хорошо ... Структуры являются типом значения, и его переменные по умолчанию не изменяются, поэтому, чтобы обойти это, было предоставлено @State
propertyWrapper
, которое в основном оборачивает значение и сохраняет и сохраняет его для нас в некотором персистенте * хранилище в рамках SwiftUI.
* Подробнее об этом см. В WWD C: https://developer.apple.com/videos/play/wwdc2019/226/
Когда @State
свойство изменяется в теле структуры View
, в которой оно было объявлено, движок SwiftUI автоматически выполняет рендеринг тела. Но если он видоизменяется извне, SwiftUI не реагирует на это.
Итак, что теперь?
Вот где @Binding
можно использовать для создания двусторонней привязки.
@ Binding
Используйте привязку для создания двустороннего соединения между свойством, которое хранит данные, и представлением, которое отображает и изменяет данные. Привязка связывает свойство с источником правды, хранящимся в другом месте, вместо непосредственного хранения данных. Например, кнопка, переключающаяся между воспроизведением и паузой, может создать привязку к свойству своего родительского представления с помощью оболочки свойств @Binding.
Ref: https://developer.apple.com/documentation/swiftui/binding
Решение:
struct SensorFamilyView: View {
@State var isActive: Bool = false
var body: some View {
VStack(alignment: .leading, spacing: 0) {
FamilyItemView(title: "Title", isActive: $isActive)
.onTapGesture {
self.isActive.toggle()
}
}
}
}
struct FamilyItemView: View {
@State var title: String
@Binding var isActive: Bool
var body: some View {
HStack {
if (isActive) {
Image(systemName: "checkmark.circle")
} else {
Image(systemName: "circle")
}
Text("\(title)")
}
}
}
SensorFamilyView
имеет свойство состояния isActive
FamilyItemView
имеет свойство привязки isActive
Между ними есть двухсторонняя привязка, поэтому, когда один меняется, другой также меняется. Кроме того, это все в рамках Combine (на котором в значительной степени основан SwiftUI), и поэтому запускается правильная последовательность событий, которая приводит к отображению тела.