来自@Published 属性的 SwiftUI 动画从视图外部更改

问题描述

SwiftUI 提供了 .animation() 绑定,可以动画视图中的更改。但是,如果来自 @Published@Observeredobject 属性“自主”更改(例如,从计时器),而视图将更新以响应更改,则没有明显的方法使视图动画化变化。

在下面的示例中,当 isOn 从 Toggle 更改时,它会动画,但从 Timer 更改时,它不会。有趣的是,如果我在这里使用三元条件而不是 if/else,即使切换也不会触发动画。

struct ContentView: View {
    @Observedobject var model: Model
    var body: some View {
        vstack {
            if model.isOn {
                MyImage(color: .blue)
            } else {
                MyImage(color: .clear)
            }
            Spacer()
            Toggle("switch",isOn: $model.isOn.animation(.easeIn(duration: 0.5)))
            Spacer()
        }
    }
}

struct MyImage: View {
    var color: Color
    var body: some View {
        Image(systemName: "pencil.circle.fill")
            .resizable()
            .frame(width: 100,height: 100)
            .foregroundColor(color)
    }
}

class Model: ObservableObject {
    @Published var isOn: Bool = false
    var timer = Timer()
    init() {
        timer = Timer.scheduledTimer(withTimeInterval: 5,repeats: true,block: { [uNowned self] _ in
            isOn.toggle()
        })
    }
}

当值更改不是来自绑定时,我如何触发动画?

解决方法

最简单的选择是在定时器闭包中添加一个 withAnimation 块:

withAnimation(.easeIn(duration: 0.5)) {
  isOn.toggle()
}

如果您无法更改@ObservableObject 闭包,您可以添加一个局部变量来反映更改:

struct ContentView: View {
    @ObservedObject var model: Model
    @State var localIsOn = false
    var body: some View {
        VStack {
            if localIsOn {
                MyImage(color: .blue)
            } else {
                MyImage(color: .clear)
            }
            Spacer()
            Toggle("switch",isOn: $model.isOn.animation(.easeIn(duration: 0.5)))
            Spacer()
        }.onChange(of: model.isOn) { (on) in
            withAnimation {
                localIsOn = on
            }
        }
    }
}

您也可以使用 ObservableObject 中的镜像变量执行类似的操作:


struct ContentView: View {
    @ObservedObject var model: Model
    var body: some View {
        VStack {
            if model.animatedOn {
                MyImage(color: .blue)
            } else {
                MyImage(color: .clear)
            }
            Spacer()
            Toggle("switch",isOn: $model.isOn.animation(.easeIn(duration: 0.5)))
            Spacer()
        }
    }
}


class Model: ObservableObject {
    @Published var isOn: Bool = false
    @Published var animatedOn : Bool = false
    
    var cancellable : AnyCancellable?
    
    var timer = Timer()
    init() {
        timer = Timer.scheduledTimer(withTimeInterval: 5,repeats: true,block: { [unowned self] _ in
                isOn.toggle()
        })
        cancellable = $isOn.sink(receiveValue: { (on) in
            withAnimation {
                self.animatedOn = on
            }
        })
    }
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...