我正在使用SwiftUI构建一个UI组件,它需要外部触发动画并做一些内部准备。以下示例中的函数 prepareArray() 用于此目的。
我最初的方法是使用绑定(bindings),但我发现没有办法监听 @Binding 变量的更改以触发某些操作:
所以我的最终方法是根据信号值触发内部状态变量:
我最初的方法是使用绑定(bindings),但我发现没有办法监听 @Binding 变量的更改以触发某些操作:
struct ParentView: View {
@State private var animated: Bool = false
var body: some View {
VStack {
TestView(animated: $animated)
Spacer()
Button(action: {
self.animated.toggle()
}) {
Text("Toggle")
}
Spacer()
}
}
}
struct TestView: View {
@State private var array = [Int]()
@Binding var animated: Bool {
didSet {
prepareArray()
}
}
var body: some View {
Text("\(array.count): \(animated ? "Y" : "N")").background(animated ? Color.green : Color.red).animation(Animation.easeIn(duration: 0.5).delay(0.1))
}
private func prepareArray() {
array = [1]
}
}
如果didSet监听器不起作用,为什么它允许用于@Binding var?然后我转而使用简单的Combine信号,因为它可以在onReceive闭包中捕获。但是,在值传递时,@State on signal未使视图失效:
struct ParentView: View {
@State private var animatedSignal = CurrentValueSubject<Bool, Never>(false)
var body: some View {
VStack {
TestView(animated: animatedSignal)
Spacer()
Button(action: {
self.animatedSignal.send(!self.animatedSignal.value)
}) {
Text("Toggle")
}
Spacer()
}
}
}
struct TestView: View {
@State private var array = [Int]()
@State var animated: CurrentValueSubject<Bool, Never>
var body: some View {
Text("\(array.count): \(animated.value ? "Y" : "N")").background(animated.value ? Color.green : Color.red).animation(Animation.easeIn(duration: 0.5).delay(0.1)).onReceive(animated) { animated in
if animated {
self.prepareArray()
}
}
}
private func prepareArray() {
array = [1]
}
}
所以我的最终方法是根据信号值触发内部状态变量:
struct ParentView: View {
@State private var animatedSignal = CurrentValueSubject<Bool, Never>(false)
var body: some View {
VStack {
TestView(animated: animatedSignal)
Spacer()
Button(action: {
self.animatedSignal.send(!self.animatedSignal.value)
}) {
Text("Toggle")
}
Spacer()
}
}
}
struct TestView: View {
@State private var array = [Int]()
let animated: CurrentValueSubject<Bool, Never>
@State private var animatedInnerState: Bool = false {
didSet {
if animatedInnerState {
self.prepareArray()
}
}
}
var body: some View {
Text("\(array.count): \(animatedInnerState ? "Y" : "N")").background(animatedInnerState ? Color.green : Color.red).animation(Animation.easeIn(duration: 0.5).delay(0.1)).onReceive(animated) { animated in
self.animatedInnerState = animated
}
}
private func prepareArray() {
array = [1]
}
}
这个方案可以工作,但我不敢相信如此简单的任务需要如此复杂的结构!我知道SwiftUI是声明式的,但也许我错过了更简单的方法来完成这个任务?实际上,在真正的代码中,这个动画触发器将不得不传递到更深一层(