TL; DR:
Я хочу вызвать действие при изменении (родительского) состояния. Это кажется трудным в декларативном контексте.
Замечания
Проблема в том, что я не пытаюсь сделать свойство одного представления зависимым по другому. Это хорошо покрытая территория. Я мог (и имел) читать весь день об обмене изменениями состояния. Но это событие .
Лучшее, с чем я столкнулся, это Арсений . Его подход работает; Мне интересно, есть ли более реактивный способ сделать это. Может быть, один выстрел Publisher
? Кажется отрывочным.
Код
«Событие» не всегда грязное слово в FRP. Я могу запустить анимацию View
, обработав событие в в том же View
:
import SwiftUI
struct MyReusableSubview : View {
@State private var offs = CGFloat.zero // Animate this.
var body: some View {
Rectangle().foregroundColor(.green).offset(y: self.offs)
// A local event triggers the action...
.onTapGesture { self.simplifiedAnimation() }
// ...but we want to animate when parent view says so.
}
private func simplifiedAnimation() {
self.offs = 200
withAnimation { self.offs = 0 }
}
}
Но я хочу, чтобы этот View
можно было компоновать и использовать повторно. Кажется разумным хотеть включить это в большую иерархию, которая будет иметь свое собственное представление о том, когда запускать анимацию. Все мои «решения» либо меняют состояние во время View
обновления, либо даже не компилируются.
struct ContentView: View {
var body: some View {
VStack {
Button(action: {
// Want this to trigger subview's animation.
}) {
Text("Tap me")
}
MyReusableSubview()
}.background(Color.gray)
}
}
Конечно, SwiftUI не заставит меня не разложить мою иерархию?
Решение
Вот предложение Арсения . Есть ли более Swifty-UI способ?
struct MyReusableSubview : View {
@Binding var doIt : Bool // Bound to parent
// ... as before...
var body: some View {
Group {
if self.doIt {
ZStack { EmptyView() }
.onAppear { self.simplifiedAnimation() }
// And call DispatchQueue to clear the doIt flag.
}
Rectangle()
.foregroundColor(.green)
.offset(y: self.offs)
}
}
}